我正在Go中编写一个服务器应用程序,并使用包装器将其作为Windows服务运行。
需要优雅地关闭服务器(以正确关闭资源和连接),在UNIX中,它将通过SIGTERM信号处理。没什么大不了。
虽然在Windows上看起来很不一样。我在this guide上看到信号实际存在于windows(?)上,并且SIGTERM已定义,但其他页面表示they don't,或者使用其他机制,如WM_CLOSE。
告诉无头进程优雅终止的最佳方法是什么?如何在Go中实现?
服务器设计为多平台,因此最常用的标准方法是这样做。
如果您正在运行某种形式的Web服务,最好使用Web服务本身来启动关闭,因为跟踪PIDS信号可能会变得混乱。
要停止http网络服务,只需添加如下路线:
http.HandleFunc("/shutdown",
func(w http.ResponseWriter, r *http.Request) {
// stops server - may want to add admin credentials check here!
srv.Shutdown(context.Background())
})
游乐场source-code的例子。
2019/03/10 16:58:15 Listening on: :8080
$ curl 'localhost:8080/shutdown'
2019/03/10 17:04:17 Listening on: :8080
2019/03/10 17:04:19 exited cleanly
go
开始取消任务/服务的方法是使用context.Context包。
因此,如果您希望信号处理程序触发任务的context.Context
关闭:
func registerSigHandler() context.Context {
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
rootCtx := context.Background()
taskCtx, cancelFn := context.WithCancel(rootCtx)
go func() {
sig := <-sigCh
log.Println("received signal:", sig)
// let sub-task know to wrap up: cancel taskCtx
cancelFn()
}()
return taskCtx
}
然后将返回的taskCtx
传递给您的工作任务,以便进行监听。
select {
case <-taskCtx.Done():
// context was canceled
default: // poll - rather than block in this example
}
游乐场source-code。
输出:
2019/03/10 19:18:51 Worker PID: 33186
2019/03/10 19:18:51 Will terminate on these signals: interrupt terminated
2019/03/10 19:18:51 2019-03-10 19:18:51.018962 -0400 EDT m=+0.001727305
2019/03/10 19:18:52 2019-03-10 19:18:52.022782 -0400 EDT m=+1.005517010
2019/03/10 19:18:53 2019-03-10 19:18:53.019925 -0400 EDT m=+2.002630457
$ kill -INT 33186
2019/03/10 19:18:53 received signal: interrupt
2019/03/10 19:18:53 task context terminated reason: context canceled
2019/03/10 19:18:53 wrapping up task...
2019/03/10 19:18:53 workerTask() exited cleanly
2019/03/10 19:18:53 main exited cleanly
编辑:
我在Windows 10
上测试了这个,当从同一个控制台发出Ctrl-C时会触发清理。不确定如何在Windows上外部发送信号 - 这可能是OP的原始问题。使用say killtask /F /PID 33186
确实会在没有触发任何信号处理程序的情况下终止进程。