問題:
你想要執行一個長-在Golang 中運行進程,同時滿足以下幾個要求:
嘗試的解決方案:
您嘗試了使用exec.Command 的解決方案,但它不滿足所有要求,特別是當您的程式收到SIGTERM/SIGKILL 訊號時。
要理解的要點:
需要注意的是,一旦啟動進程,您就無法更改其父進程 - 進程的父子關係是固定的。
替代庫:
建議使用解決此問題的現有庫,而不是重新發明輪子。建議使用以下函式庫:
使用go-reap 的範例:
<code class="go">import ( "fmt" "os" "os/exec" "strings" "sync" "time" "github.com/fatih/color" "github.com/hashicorp/go-reap" ) func main() { if reap.IsSupported() { done := make(chan struct{}) var reapLock sync.RWMutex pids := make(reap.PidCh, 1) errors := make(reap.ErrorCh, 1) go reap.ReapChildren(pids, errors, done, &reapLock) go report(pids, errors, done) // Here is where you would start your long-running process Sh() close(done) } else { fmt.Println("Sorry, go-reap isn't supported on your platform.") } } func report(pids reap.PidCh, errors reap.ErrorCh, done chan struct{}) { sprintf := color.New(color.FgWhite, color.Bold).SprintfFunc() for ;; { select { case pid := <-pids: println(sprintf("raeper pid %d", pid)) case err := <-errors: println(sprintf("raeper er %s", err)) case <-done: return } } } func Sh() { args := os.Args[1:] script := args[0:0] if len(args) >= 1 { if args[0] == "-c" { script = args[1:] } } if len(script) == 0 { fn.CyanBold("cmd: expecting sh -c 'foobar'") os.Exit(111) } var cmd *exec.Cmd parts, _ := shlex.Split(strings.Join(script, " ")) if len(parts) >= 2 { cmd = fn.Merge(exec.Command(parts[0], parts[1:]...), nil) } if len(parts) == 1 { cmd = fn.Merge(exec.Command(parts[0]), nil) } // ... Here you can customize how the process is started and controlled if fn.IfEnv("HANG") { fn.CyanBold("cmd: %v\n start", parts) ex := cmd.Start() if ex != nil { fn.CyanBold("cmd %v err: %s", parts, ex) } go func() { time.Sleep(time.Millisecond * 100) errw := cmd.Wait() if errw != nil { fn.CyanBold("cmd %v err: %s", parts, errw) } else { fn.CyanBold("cmd %v all done.", parts) } }() fn.CyanBold("cmd: %v\n dispatched, hanging forever (i.e. to keep docker running)", parts) for { time.Sleep(time.Millisecond * time.Duration(fn.EnvInt("HANG", 2888))) fn.SystemCyan("/bin/ps", "-e", "-o", "stat,comm,user,etime,pid,ppid") } } else { if fn.IfEnv("NOWAIT") { ex := cmd.Start() if ex != nil { fn.CyanBold("cmd %v start err: %s", parts, ex) } } else { ex := cmd.Run() if ex != nil { fn.CyanBold("cmd %v run err: %s", parts, ex) } } fn.CyanBold("cmd %v\n dispatched, exit docker.", parts) } }</code>
此範例使用go-reap 啟動shell(Sh() 函數)並在該shell 中執行命令。它設定收割機來處理子進程的清理。
透過使用信譽良好的函式庫,您可以避免常見的陷阱並確保您的應用程式能如預期運作。
以上是如何在 Golang 中執行長時間運行的進程並將其與我的程式分離,同時控制使用者、重定向輸出並防止其成為殭屍進程?的詳細內容。更多資訊請關注PHP中文網其他相關文章!