golang:如何在 k8s 容器中优雅地关闭/中断 for 循环

问题描述 投票:0回答:1

我是 golang 新手。 我有一个 go 程序,它是一个 for 循环,就像

for {
  f()
}

f
可能需要几秒钟到 1 分钟。 for 循环永远运行,并且可以被 KILL 信号终止。

在 k8s 容器中,我们可能会经常杀死程序/进程。所以我希望 KILL 信号仅在函数

f
完成且未启动后中断 for 循环。

如何做到这一点?有例子吗?

谢谢

go kubernetes sigkill
1个回答
0
投票

要对信号执行某些操作,您将需要一些侦听信号的代码。请注意,您无法监听 SIGKILL,但这不是您的应用程序收到的信号(除非使用类似

kill $PID
的信号)。在大多数情况下,您的应用程序将收到 SIGTERM。

最简单的聆听方法如下:

quit := make(chan os.Signal, 1) // Create a channel for the signal
signal.Notify(quit, os.Interrupt, syscall.SIGTERM) // Instruct the runtime to send signals to that channel
<-quit // Read from the channel. This operation blocks until there is something to read

接下来,您需要将其与无限循环结合起来。我们可以使用

select
来实现这一点。
select
switch
类似,不同之处在于它会检查每个
case
是否有“那里还有东西”;如果没有任何一种情况,则
default
被执行。非常完美:您可以使用
case
检查是否收到信号,否则使用
default
执行您的函数。

quit := make(chan os.Signal, 1)
signal.Notify(quit, os.Interrupt, syscall.SIGTERM)

for {
  select {
    case <-quit:
      return
    default:
      f()
  }
}

对于小型、单一用途的应用程序,上述内容可能已经足够了。

对于较大的应用程序,通常创建一个“根上下文”,使用

context.WithCancel()
包装它,将该 ctx 传递到所有 goroutine 中。每个 goroutine 不是直接监听信号,而是检查
<-ctx.Done()
。主 Goroutine(或单独的专用 Goroutine)侦听操作系统信号并调用
context.WithCancel()
返回的取消函数。

后来的设置不仅更具可扩展性,而且还可以与外部代码很好地配合使用;例如,如果应用程序正在关闭,

database/sql.DB.QueryContext()
会执行相同的技巧检查
<-ctx.Done()
以停止正在执行的操作。

© www.soinside.com 2019 - 2024. All rights reserved.