Go
golang

goroutine にシグナルを送信する

More than 1 year has passed since last update.

正確には goroutine へ直接シグナルを送る方法なんてありませんが、次のパッケージを使うことで似たようなことを実現することができます。(タイトルで釣ってしまって申し訳ないです!!)

Code-Hex/sigctx - GitHub  GitHub stars


context with signal in golang


シグナル受信するための context を作成することができるパッケージです。


あるシグナルをプロセスが受け取ったら context cancel を行う

package main

import (
"context"
"fmt"
"sync"
"syscall"

"github.com/Code-Hex/sigctx"
)

func main() {

ctx := sigctx.WithCancelSignals(
context.Background(),
syscall.SIGINT,
syscall.SIGTERM,
syscall.SIGHUP,
)

var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for {
select {
// You can cancel by send signal.
case <-ctx.Done():
fmt.Println(ctx.Err())
return
}
}
}()
}
wg.Wait()
}

sigctx.WithCancelSignals の第一引数に context.Context を、その後ろに context キャンセルを行わせたい os.Signal を指定します。(この場合だと INT, TERM, HUP を受信すると context キャンセルを行います)

めっちゃシンプルですね!


受け取ったシグナルを context を使っている全ての goroutine へ通知する

package main

import (
"context"
"fmt"
"sync"
"syscall"

"github.com/Code-Hex/sigctx"
)

func main() {

ctx := sigctx.WithSignals(
context.Background(),
syscall.SIGINT,
syscall.SIGTERM,
syscall.SIGHUP,
)

var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for {
select {
// You can notify signal received.
case <-sigctx.Recv(ctx):
signal, err := sigctx.Signal(ctx)
if err != nil {
fmt.Println(err.Error())
return
}
switch signal {
case syscall.SIGINT:
fmt.Println(signal.String())
return
default:
fmt.Println(signal.String())
}
case <-ctx.Done():
fmt.Println(ctx.Err())
return
}
}
}()
}
wg.Wait()
}

sigctx.WithSignalssigctx.Recv を使うことで通知が可能になります。

sigctx.Recv の引数には「sigctx.WithSignals の返り値の context.Context」を渡すことで実現可能です。

また受信したシグナルを受け取るには sigctx.Signal を使うと受け取ることができます。sigctx.Signal の引数も「sigctx.WithSignals の返り値の context.Context」をわたうようにしてください。

この辺はもう少し工夫すればもっとシンプルになりそうですが、もっと良いアイデアお持ちの方がいましたら是非 PR を送っていただけると嬉しいです。

是非使ってみてください!