doulv8162 2015-02-07 23:30
浏览 88

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

I'm writing a little program to manage restarts to other processes.

Basically when an app process starts (call it A), it spawns a new process (call it D), which has a simple HTTP server. When D receives an http request, it kills A and restarts it.

Problem is, A now doesn't respond to CTRL-C, and I'm not sure why. It may be something simple or maybe I don't really understand the relationship between processes, the terminal, and signals. But it's running in the same terminal with the same stdin/stdout/stderr. Below is a full program demonstrating this behaviour.

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")
    }
}

The program expects to be installed. For convenience you can fetch it with go get github.com/ebuchman/restarter.

Run the program with restarter. It should print its process id. Then curl http://localhost:9999/<procid> to initiate the restart. The new process will now not respond to CTRL-C. Why? What am I missing?

  • 写回答

2条回答 默认 最新

  • dongtanzhu5417 2015-02-08 08:02
    关注

    You can check out the approach taken by two http server frameworks in order to listen and intercept signals (including SIGINT, or even SIGTERM)

    评论

报告相同问题?

悬赏问题

  • ¥15 微信小程序协议怎么写
  • ¥15 c语言怎么用printf(“\b \b”)与getch()实现黑框里写入与删除?
  • ¥20 怎么用dlib库的算法识别小麦病虫害
  • ¥15 华为ensp模拟器中S5700交换机在配置过程中老是反复重启
  • ¥15 java写代码遇到问题,求帮助
  • ¥15 uniapp uview http 如何实现统一的请求异常信息提示?
  • ¥15 有了解d3和topogram.js库的吗?有偿请教
  • ¥100 任意维数的K均值聚类
  • ¥15 stamps做sbas-insar,时序沉降图怎么画
  • ¥15 买了个传感器,根据商家发的代码和步骤使用但是代码报错了不会改,有没有人可以看看