context について調べたので試しにos.Signal を受け取るとキャンセルを実行するcontext.WithCancelBySignal()を作った。
書いてから振り返るとcontext はトランザクション単位で用いるがos.Signal はプロセス全体に関わるため概念が一致しづらい。
exec.CommandContext() はSIGKILL を飛ばしてしまうので子プロセスは直ちに死ぬ。そのままでは使えず相性が悪い。
ただ作ったのでとりあえず残す。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
// WithCancelBySignal returns context cancelable by signal
func WithCancelBySignal(parent context.Context, sigs ...os.Signal) (ctx context.Context) {
ctx, cancel := context.WithCancel(parent)
go func() {
sc := make(chan os.Signal)
signal.Notify(sc, sigs...)
select {
case <-ctx.Done():
case <-sc:
}
cancel()
}()
return ctx
}
func main() {
ctx := WithCancelBySignal(context.Background(), syscall.SIGTERM)
LOOP:
for {
select {
case <-ctx.Done():
break LOOP
default:
}
fmt.Println("in loop")
}
}
|