为了账号安全,请及时绑定邮箱和手机立即绑定

golang 重新启动的父进程没有收到 SIGINT

golang 重新启动的父进程没有收到 SIGINT

Go
沧海一幻觉 2021-09-13 15:58:56
我正在编写一个小程序来管理其他进程的重启。基本上,当一个应用程序进程启动(称为 A)时,它会产生一个新进程(称为 D),它有一个简单的 HTTP 服务器。当 D 收到一个 http 请求时,它会杀死 A 并重新启动它。问题是,A 现在不响应 CTRL-C,我不知道为什么。可能很简单,也可能我不太了解进程、终端和信号之间的关系。但它在具有相同标准输入/标准输出/标准错误的同一个终端中运行。下面是一个演示这种行为的完整程序。package mainimport (    "flag"    "log"    "net/http"    "os"    "os/exec"    "strconv"    "time")/*    Running this program starts an app (repeatdly prints 'hi') and spawns a new process running a simple HTTP server    When the server receives a request, it kills the other process and restarts it.    All three processes use the same stdin/stdout/stderr.    The restarted process does not respond to CTRL-C :(*/var serv = flag.Bool("serv", false, "run server")// run the app or run the serverfunc main() {    flag.Parse()    if *serv {        runServer()    } else {        runApp()    }}// handle request to server// url should contain pid of process to restartfunc handler(w http.ResponseWriter, r *http.Request) {    pid, err := strconv.Atoi(r.URL.Path[1:])    if err != nil {        log.Println("send a number...")    }    // find the process    proc, err := os.FindProcess(pid)    if err != nil {        log.Println("can't find proc", pid)        return    }    // terminate the process    log.Println("Terminating the process...")    err = proc.Signal(os.Interrupt)    if err != nil {        log.Println("failed to signal interupt")        return    }    // restart the process    cmd := exec.Command("restarter")    cmd.Stdin = os.Stdin    cmd.Stdout = os.Stdout    cmd.Stderr = os.Stderr    if err := cmd.Start(); err != nil {        log.Println("Failed to restart app")        return    }    log.Println("Process restarted")}该程序预计将被安装。为方便起见,您可以使用go get github.com/ebuchman/restarter.运行程序restarter。它应该打印其进程 ID。然后curl http://localhost:9999/<procid>启动重启。新进程现在不会响应 CTRL-C。为什么?我错过了什么?
查看完整描述

2 回答

?
慕盖茨4494581

TA贡献1850条经验 获得超11个赞

这与 Go 没有任何关系。您从终端外壳启动进程 A。进程 A 启动进程 D(不确定 B 发生了什么,但没关系)。进程 D 杀死进程 A。现在你的 shell 看到它启动的进程已经退出,所以 shell 准备听另一个命令。进程 D 启动进程 A 的另一个副本,但外壳对此一无所知。当您键入 ^C 时,shell 将处理它。如果你运行另一个程序,shell 会安排 ^C 去那个程序。shell 对进程 A 的副本一无所知,因此它永远不会将 ^C 指向该进程。

查看完整回答
反对 回复 2021-09-13
?
人到中年有点甜

TA贡献1895条经验 获得超7个赞

您可以查看两个 http 服务器框架采用的方法来侦听和拦截信号(包括SIGINT,甚至SIGTERM)


kornel661/nserv,其中ZeroDowntime-example/server.go使用通道:


// catch signals:

signals := make(chan os.Signal)

signal.Notify(signals, os.Interrupt, os.Kill)

zenazn/goji,其中graceful/signal.go使用类似的方法:


var stdSignals = []os.Signal{syscall.SIGINT, syscall.SIGTERM}

var sigchan = make(chan os.Signal, 1)

func init() {

    go waitForSignal()

}


查看完整回答
反对 回复 2021-09-13
  • 2 回答
  • 0 关注
  • 198 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信