はい![]()
今回ご紹介するのは、こちらのnasa9084/sygです。
https://github.com/nasa9084/syg
- Golang: 手軽にシグナルをListenしてcallback関数を呼ぶ
https://blog.web-apps.tech/go-signal-more-simply/
これを使えば、HTTPサーバがexit(停止)する前に、任意のコードを仕込めてしまいます。
ありがてぇ…ありがてぇ…
経緯
GoでHTTPのRESTAPIサービスを作っていて、その中でRedisのコネクションをプールして使いまわす機能を作りました。
そうするとやっぱ、サービスが終了(HTTPサーバが停止)するときにコネクションをちゃんと開放しなきゃですよ。
「でも、http.ListenAndServeを実行してるところにdefer funcを仕掛けりゃいいだけッスよね? ちょろいちょろい♪」
とナメていたら…
defer funcが実行されない!!
どうやらos.Exit(code int)が発動すると、deferがかき消されてしまうとのこと。なんてこったい![]()
そこで見つけたのがこちらになります。
用例
例えばこんな感じで、シグナルを受け取ったときに発動するコールバック関数に、好きな後始末処理を仕込むだけ![]()
私の場合は、プールしてるRedisのコネクションをClose()してます。
package main
import (
"context"
"fmt"
"github.com/go-redis/redis"
"net/http"
"os"
"github.com/nasa9084/syg"
)
var pooledKVSConnectionsMap = make(map[*redis.Options]*redis.Client)
func main() {
s := &http.Server{Addr: ":8080"}
waitCh := make(chan struct{})
cancel := syg.Listen(func(os.Signal) {
s.Shutdown(context.Background())
destruct() // <--- 仕込み!
close(waitCh)
}, os.Interrupt)
defer cancel()
if err := s.ListenAndServe(); err != http.ErrServerClosed {
fmt.Print("listening server error:" + err.Error())
}
<-waitCh
}
func destruct() {
for _, kvsCon := range pooledKVSConnectionsMap {
cerr := kvsCon.Close()
if cerr != nil {
fmt.Print(cerr)
} else {
fmt.Print(kvsCon, " ... closed.")
}
}
}
ご注意
github.com/nasa9084/sygのREADME.mdがちょっと古いのか、そちらの例ではdefer cancel()のコードが抜けているので、作者様サイトの例コードやsyg_example_test.goなどを参照されると良いかと思います。
さいごに
・・・
というか、そもそも間違ってました・・・
いえ、この記事そのものではないのですが、go-redis/redisはあらかじめコネクションプールの仕組みを内包しており、使い手側は気にせずNewClient(), Close()をして良いそうです![]()
実際goroutineを使ってNewClient(), Close()を毎度呼ぶコードと比較したのですが、全く問題ありませんでした。
・・・まあ、勉強になったからよし!