11
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

golangでシグナルを拾ってgracefulにgoroutineを停めたい・改

Last updated at Posted at 2015-11-10

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`
11
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?