【问题标题】:In Golang, how to terminate an os.exec.Cmd process with a SIGTERM instead of a SIGKILL?在 Golang 中,如何使用 SIGTERM 而不是 SIGKILL 终止 os.exec.Cmd 进程?
【发布时间】:2021-07-23 04:57:14
【问题描述】:

目前,我正在使用 Golang os.exec.Cmd.Process.Kill() 方法终止一个进程(在 Ubuntu 机器上)。

这似乎会立即终止进程,而不是优雅地终止。我正在启动的一些进程也会写入文件,这会导致文件被截断。

我想用 SIGTERM 而不是使用 Golang 的 SIGKILL 优雅地终止进程。

这是一个使用 cmd.Process.Kill() 启动然后终止的进程的简单示例,我想要在 Golang 中替代使用 SIGTERM 而不是 SIGKILL 的 Kill() 方法,谢谢!

import "os/exec"

cmd := exec.Command("nc", "example.com", "80")
if err := cmd.Start(); err != nil {
   log.Print(err)
}
go func() {
  cmd.Wait()
}()
// Kill the process - this seems to kill the process ungracefully
cmd.Process.Kill()

【问题讨论】:

标签: linux go ubuntu process operating-system


【解决方案1】:

您可以使用Signal() API。支持的Syscalls 在这里。

所以基本上你可能想要使用

cmd.Process.Signal(syscall.SIGTERM)

另外请按照文档说明。

唯一保证存在于 os 包中的信号值 所有系统都是 os.Interrupt (向进程发送中断)和 os.Kill(强制进程退出)。在 Windows 上,发送 os.Interrupt 没有实现 os.Process.Signal 的进程;它会回来 错误而不是发送信号。

【讨论】:

    【解决方案2】:
    cmd.Process.Signal(syscall.SIGTERM)
    

    【讨论】:

      【解决方案3】:

      你可以使用:

      cmd.Process.Signal(os.Interrupt)
      

      测试示例:

      package main
      
      import (
          "fmt"
          "log"
          "net"
          "os"
          "os/exec"
          "sync"
          "time"
      )
      
      func main() {
          cmd := exec.Command("nc", "-l", "8080")
          cmd.Stderr = os.Stderr
          cmd.Stdout = os.Stdout
          cmd.Stdin = os.Stdin
          err := cmd.Start()
          if err != nil {
              log.Fatal(err)
          }
      
          var wg sync.WaitGroup
          wg.Add(1)
          go func() {
              err := cmd.Wait()
              if err != nil {
                  fmt.Println("cmd.Wait:", err)
              }
              fmt.Println("done")
              wg.Done()
          }()
      
          fmt.Println("TCP Dial")
          fmt.Println("Pid =", cmd.Process.Pid)
          time.Sleep(200 * time.Millisecond)
          // or comment this and use: nc 127.0.0.1 8080
          w1, err := net.DialTimeout("tcp", "127.0.0.1:8080", 1*time.Second)
          if err != nil {
              log.Fatal("tcp DialTimeout:", err)
          }
          defer w1.Close()
      
          fmt.Fprintln(w1, "Hi")
          time.Sleep(1 * time.Second)
          // cmd.Process.Kill()
          cmd.Process.Signal(os.Interrupt)
          wg.Wait()
      }
      

      输出:

      TCP Dial
      Pid = 21257
      Hi
      cmd.Wait: signal: interrupt
      done
      

      【讨论】:

      • 我需要 SIGTERM,所以 syscall.SIGTERM 为我的用例做了诀窍,但这也是一个很棒的答案,os.Interrupt 在某些情况下也会非常有用,谢谢你的例子。
      猜你喜欢
      • 1970-01-01
      • 2017-03-01
      • 2011-02-26
      • 2010-10-15
      • 2013-07-03
      • 1970-01-01
      • 2014-09-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多