我正在編寫一個小程序來管理重啓到其他進程。golang重啓父進程沒有收到SIGINT
基本上,當一個應用程序進程啓動(稱爲A)時,它會產生一個新的進程(稱爲D),它具有一個簡單的HTTP服務器。當D接收到一個http請求時,它殺死A並重新啓動它。
問題是,現在不響應CTRL-C,我不知道爲什麼。這可能是一些簡單的事情,也可能我並不真正瞭解進程,終端和信號之間的關係。但它使用相同的stdin/stdout/stderr在同一終端中運行。以下是展示此行爲的完整程序。
package main
import (
"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 server
func main() {
flag.Parse()
if *serv {
runServer()
} else {
runApp()
}
}
// handle request to server
// url should contain pid of process to restart
func 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")
}
// run the server.
// this will only work the first time and that's fine
func runServer() {
http.HandleFunc("/", handler)
if err := http.ListenAndServe(":9999", nil); err != nil {
log.Println(err)
}
}
// the app prints 'hi' in a loop
// but first it spawns a child process which runs the server
func runApp() {
cmd := exec.Command("restarter", "-serv")
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Start(); err != nil {
log.Println(err)
}
log.Println("This is my process. It goes like this")
log.Println("PID:", os.Getpid())
for {
time.Sleep(time.Second)
log.Println("hi again")
}
}
該程序預計將被安裝。爲方便起見,您可以使用go get github.com/ebuchman/restarter
來獲取。
使用restarter
運行該程序。它應該打印它的進程ID。然後curl http://localhost:9999/<procid>
啓動重啓。新進程現在不會響應CTRL-C。爲什麼?我錯過了什麼?
不幸的是,這並沒有幫助。問題不在於該過程沒有處理信號的處理程序,而是信號根本沒有進入該過程,因爲它處於由其孩子重新啓動的奇怪狀態。這就像終端已經失去了過程的鉤子,但pgid的沒有改變。 – Ethan 2015-02-08 20:35:41