给定我下面的程序,什么是一个好的做法,使方法取消(service.Start()
)完成(即。打印 * 完成 *)之前,通过调用cancel()
函数终止?我只有一个Go例程,所以使用WaitGroup
感觉不对。当我注解掉main()
函数中的最后一行(time.Sleep
)时,程序似乎过早地结束了,因为service.Start()
没有打印 Done。如果我取消注解2秒睡眠,那么 Done 就会被打印出来。我只是想找到实现取消方法的最佳实践,以完成而不提前终止程序,但使用WaitGroup
或time.Sleep()
对我来说似乎是这个特定程序的一个坏做法。我使用Go例程和退出通道的原因是因为service.Start()
将包含需要定期运行的逻辑,直到程序停止。
main:
func main() {
log.Infoln("starting service..")
ctx := context.Background()
srv := service.Service{}
exitCh := make(chan os.Signal, 1)
signal.Notify(exitCh, syscall.SIGTERM, // terminate: stopped by `kill -9 PID`
syscall.SIGINT, // interrupt: stopped by Ctrl + C
)
ctxCancel, cancel := context.WithCancel(ctx)
go run(ctxCancel, srv, exitCh)
<-exitCh // blocking until receive exit signal
cancel()
time.Sleep(time.Second * 2)
}
func run(ctx context.Context, srv service.Service, exitCh chan<- os.Signal) {
defer func() {
exitCh <- syscall.SIGTERM // send terminate signal when application stop naturally
}()
err := srv.Start(ctx)
if err != nil {
log.Warningf("canceling all operations: %s", err)
}
}
服务:
type Service struct {}
func (s *Service) Start(ctx context.Context) error {
for i := 0; i < 5; i++ {
select {
case <-ctx.Done():
log.Println("Done")
return ctx.Err()
default:
log.Printf("i value: %d", i)
time.Sleep(3 * time.Second)
}
}
return nil
}
1条答案
按热度按时间7gcisfzg1#
在每个服务自己的例程中运行每个服务是一个很好的实践,在这个例程中,通过返回来确认关闭。函数或方法签名为Run-not Start-因为上下文参数适用于整个服务持续时间。
在
main
中使用“Done”回调通道启动每个服务:SIGTERM不是
kill -9
,正如评论所说。SIGKIL是。SIGKILL不能等待几秒钟完成,但SIGINT和SIGTERM可能应该。继续
main
退出处理:退出代码约定当然是可选的,但它允许重启逻辑等。我把退出密码作为手册的一部分。