概要
go-workers でシグナルをハンドリングする方法を紹介します
環境
- macOS 10.14.6
- go 1.12.9
- go-workers dbf81d0b75bbe2fd90ef66a07643dd70cb42a88a
go-workers 内でハンドリングしてくれるシグナル
実は go-workers 内でも特定の Ctrl+c などのシグナルはハンドリングしてくれています
func handleSignals() {
signals := make(chan os.Signal, 1)
signal.Notify(signals, syscall.SIGUSR1, syscall.SIGINT, syscall.SIGTERM)
for sig := range signals {
switch sig {
case syscall.SIGINT, syscall.SIGUSR1, syscall.SIGTERM:
Quit()
}
}
}
この関数はワーカーが Run()
した際に goroutine として実行されています
Ctrl+c は syscall.SIGINT
になります
やっていることは単純で Quit()
という処理を実行してワーカーが正しく終了されるような処理を実行しています
ただ SIGHUP などはハンドリングしていないのでワーカーに SIGHUP を送信すると「Hungup: 1」と表示されて終了してしまいます
しかも go run で実行しているとビルドのプロセスが残ってしまい面倒なことになります
なので他のシグナルも本当はちゃんとハンドリングしてあげる必要がありそうです
SIGHUP をハンドリングしてみる
試しに SIGHUP を追加でハンドリングできるようにしていみます
特にライブラリに手を入れる必要はなくワーカー側でハンドリングするようにすれば OK です
package main
import (
"os"
"os/signal"
"syscall"
"github.com/jrallison/go-workers"
)
func handleSignals() {
signals := make(chan os.Signal, 1)
signal.Notify(signals, syscall.SIGHUP)
for sig := range signals {
switch sig {
case syscall.SIGHUP:
workers.Logger.Println("sighup")
}
}
}
func perform(msg *workers.Msg) {
c, _ := msg.Args().Int()
for i := 0; i < c; i++ {
workers.Logger.Println(i)
}
workers.Logger.Println("end")
}
func main() {
workers.Configure(map[string]string{
"server": "localhost:6379",
"process": "1",
})
workers.Process("default", perform, 1)
go handleSignals()
workers.Run()
}
handleSignals
関数をそのまま使って syscall.SIGHUP
をハンドリングできるようにします
また main()
内で Run()
する前に goroutine として関数を実行しておきます
動作確認
ワーカーを起動して SIGHUP シグナルを送信してみましょう
go fmt ./... && go build worker.go && ./worker
kill -SIGHUP `ps aux | grep './worker' | grep -v grep | awk '{print $2}'`
こんな感じで表示されます
またハンドリングしていない場合はプロセス自体が終了していたのですが今度は終了しなくなったと思います
SIGINT を独自にハンドリングしてみる
go-workers 側で SIGINT をハンドリングしていますが自信でもハンドリングしたいケースはあると思います
先程のワーカーの handleSignals
関数に syscall.SIGINT
も追加してみます
func handleSignals() {
signals := make(chan os.Signal, 1)
signal.Notify(signals, syscall.SIGHUP, syscall.SIGINT)
for sig := range signals {
switch sig {
case syscall.SIGHUP:
workers.Logger.Println("sighup")
case syscall.SIGINT:
workers.Logger.Println("sigint")
}
}
}
動作確認
go fmt ./... && go build worker.go && ./worker
kill -SIGINT `ps aux | grep './worker' | grep -v grep | awk '{print $2}'`
ちゃんと SIGINT を独自でハンドリングできました
が、独自のハンドラを抜けてライブラリ側のハンドラーにも行ってしまうようでワーカーは終了してしまいました
たぶん golang の仕様だと思うのですがシグナルのハンドラが複数 goroutine で動いている場合はすべての goroutine がシグナルをキャッチできるんだと思います
なので使い方としては SIGINT の終了前に何か処理をしたい場合に使う感じかなと思います
最後に
go-workers でシグナルをハンドリングする方法を紹介しました
コードを見ると AfterQuit
という関数がコメントアウトされていたので始めはミドルウェア的な使い方でハンドリングできるのかなと思ったのですがどうやらダメそうです
今回紹介した方法はライブラリ側でシグナルハンドリングが行われる前に何かする方法になります
なのでライブラリ側で処理した後に何かしたい場合は直接コードを書き換えるしかなさそうで
0 件のコメント:
コメントを投稿