概要
よく忘れるのでメモメモ。
少し前に exec.Command について以下をメモしていました。
上の記事では 、コマンドの実行に exec.Command() を利用していましたが、context.Context を指定できる exec.CommandContext() というのもあります。こちらを利用すると、渡した context.Context が Done したタイミングでまだ実行中だった場合に kill signal を送って終了してくれます。
サンプル
package cmdexec import ( "context" "errors" "os/exec" "runtime" "time" "github.com/devlights/gomy/output" ) // WithContext は、context.Context 付きでコマンドを実行するサンプルです。 func WithContext() error { if runtime.GOOS == "windows" { return errors.New("this example cannot run on Windows, sorry") } const ( Shell = "/bin/bash" ) var ( rootCtx = context.Background() mainCtx, mainCxl = context.WithCancel(rootCtx) procCtx, procCxl = context.WithTimeout(mainCtx, 500*time.Millisecond) ) defer mainCxl() defer procCxl() var ( cmd *exec.Cmd // コマンド err error // エラー ) // // コマンドは2秒かかるようにして実行するが、渡している context は 500ms でタイムアウトする // cmd = exec.CommandContext(procCtx, Shell, "-c", "sleep 2") err = cmd.Run() if err != nil { var exitErr *exec.ExitError if errors.Is(procCtx.Err(), context.DeadlineExceeded) && errors.As(err, &exitErr) { output.Stdoutf("[timeout]", "%[1]v(%[1]T)\n", err) return nil } else { return err } } return nil }
try-golang/withcontext.go at master · devlights/try-golang · GitHub
実行すると以下のようになります。
gitpod /workspace/try-golang $ make run go get -d ./... go run -race github.com/devlights/try-golang/cmd/trygolang -onetime -example "" ENTER EXAMPLE NAME: cmdexec_withc [Name] "cmdexec_withcontext" [timeout] signal: killed(*exec.ExitError) [Elapsed] 502.113094ms
2秒かからずに渡した context が done したタイミングで終了してくれていますね。
参考資料
過去の記事については、以下のページからご参照下さい。
- いろいろ備忘録日記まとめ
サンプルコードは、以下の場所で公開しています。
- いろいろ備忘録日記サンプルソース置き場