golangでシグナルを拾ってgracefulにgoroutineを停めたい・改
これの続き。
http://qiita.com/arc279/items/c44d4a18a851ff454c64
ちょっとまとめてみた。名前は適当。
使い方は main()
を見られたし。
main.go
package main
import (
"fmt"
"os"
"os/signal"
"sync"
"syscall"
"time"
)
type Gracefully struct {
trapSig []os.Signal
callback func(os.Signal) bool
procs []func()
}
func NewGracefully(callback func(os.Signal) bool, sig ...os.Signal) *Gracefully {
self := Gracefully{
trapSig: sig,
callback: callback,
procs: make([]func(), 0),
}
return &self
}
func (self *Gracefully) Append(proc func()) {
self.procs = append(self.procs, proc)
}
func (self *Gracefully) Run() {
var wg sync.WaitGroup
wg.Add(len(self.procs))
exitChan := make([]chan int, len(self.procs))
for i, _ := range self.procs {
exitChan[i] = make(chan int, 1)
}
for i, proc := range self.procs {
go func(ch chan int, proc func()) {
defer wg.Done()
for {
select {
case <-ch:
return
default:
// なんらかの並行処理するやつ
proc()
}
}
}(exitChan[i], proc)
}
signalChan := make(chan os.Signal)
signal.Notify(signalChan, self.trapSig...)
go func() {
for {
sig := <-signalChan
for _, trap := range self.trapSig {
if sig == trap {
if self.callback(sig) {
// callbackがtrueを返したら抜ける
for _, c := range exitChan {
c <- 1
}
}
}
}
}
}()
wg.Wait()
}
func main() {
// HUP と USR2 を拾って、HUPの時は抜けたいコールバック
g := NewGracefully(func(sig os.Signal) bool {
fmt.Println(sig)
return sig == syscall.SIGHUP
}, syscall.SIGHUP, syscall.SIGUSR2)
procs := []string{
"proc1",
"proc2",
"proc3",
"proc4",
"proc5",
"proc6",
"proc7",
}
for _, p := range procs {
// javascriptみたいw
g.Append(func(s string) func() {
return func() {
fmt.Println(s)
time.Sleep(500 * time.Millisecond)
}
}(p))
}
g.Run()
fmt.Println("stop gracefully")
os.Exit(0)
}
ビルドして実行
$ go build -o sample main.go && ./sample
シグナルを送る
HUPだと停まる
$ kill -SIGHUP `pgrep -f sample`
USR2だと停まらない
$ kill -SIGUSR2 `pgrep -f sample`
それ以外は拾わない
$ kill -SIGUSR1 `pgrep -f sample`