問題:
長いコマンドを実行したいと考えています。いくつかの要件を満たしながら 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 を使用してシェル (Sh() 関数) を開始し、そのシェル内でコマンドを実行します。子プロセスのクリーンアップを処理するようにリーパーを設定します。
評判の良いライブラリを使用することで、よくある落とし穴を回避し、アプリケーションが意図したとおりに動作することを保証できます。
以上がGolang で長時間実行プロセスを実行し、ユーザーを制御し、出力をリダイレクトし、ゾンビになるのを防ぎながら、それをプログラムから切り離すにはどうすればよいでしょうか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。