假设我的Uber FX应用程序中有一个服务,它应该执行一些后台活动,比如轮询外部API。我可以通过触发goroutine来运行后台任务,但是如何正确地停止它们呢?
作为一种可能的实现,让我们考虑以下示例:
package main
import (
"context"
"log"
"sync"
"time"
"go.uber.org/fx"
)
type AwesomeService struct {
// context to use for background processes
bg context.Context
// to trigger background processes stopping
cancel context.CancelFunc
// to wait for background processes to gracefully finish
wg *sync.WaitGroup
}
func New(lc fx.Lifecycle) *AwesomeService {
bg, cancel := context.WithCancel(context.Background())
service := &AwesomeService{
bg: bg,
cancel: cancel,
wg: new(sync.WaitGroup),
}
lc.Append(fx.Hook{
OnStart: service.start,
OnStop: service.stop,
})
return service
}
func (s *AwesomeService) start(_ context.Context) error {
s.runBackgroundProcess()
log.Println("Start done")
return nil
}
func (s *AwesomeService) stop(_ context.Context) error {
s.cancel()
s.wg.Wait()
log.Println("Stop done")
return nil
}
// runBackgroundProcess does some work till context is done.
func (s *AwesomeService) runBackgroundProcess() {
s.wg.Add(1)
go func() {
defer s.wg.Done()
for {
select {
case <-s.bg.Done():
return
case <-time.After(1 * time.Second):
log.Println("Working...")
}
}
}()
}
func main() {
fx.New(
fx.Provide(New),
fx.Invoke(func(*AwesomeService) {}),
).Run()
}
字符串
注意事项:
- 通过使用
fx.Lifecycle
挂钩,服务与应用程序生命周期相关联。 - 我不能依赖和使用
OnStart
/OnStop
方法中的上下文,因为它们是不同的上下文,并且对应于启动/停止活动,而不是应用生命周期上下文。
关注和问题:
- 在跟踪bg任务方面,给出的例子是相当繁重的。而且,在结构中存储上下文是一种反模式。有没有什么方法可以简化它?
- 我是否应该等待goroutine完成,以防没有资源可以释放?
1条答案
按热度按时间a9wyjsp71#
在我看来,使用上下文是很好的,但是你也可以通过一个通道向任何你想要的Go例程传递一个关闭信号。
是的,你也应该等待等待组计数返回到零之前完全关闭应用程序.所以你会先关闭通道,然后等待等待组.
字符串