はじめに
Go の Gin を使ってみて、 Graceful shutdown するにはどうするだろうと調べたメモです。
目次
環境
go 1.20 で試してます。
% go version go version go1.20 linux/amd64
サンプル
Gin のドキュメントにサンプルの記載がありました。
また、GitHub にもサンプルがありました。
ほぼサンプル通りですが適当なディレクトリ配下に以下のような main.go
を作成&配置して試してみます。
package main import ( "context" "log" "net/http" "os" "os/signal" "syscall" "time" "github.com/gin-gonic/gin" ) func main() { // ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) defer stop() router := gin.Default() router.GET("/hello", helloHandler) srv := &http.Server{ Addr: ":8080", Handler: router, } // ゴルーチンで http サーバーを起動させる go func() { if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatalf("listen: %s\n", err) } }() <-ctx.Done() stop() log.Println("shutting down gracefully, press Ctrl+C again to force") // Background()コンテキストを生成する。 // 指定された時間内(ここでは5秒)に操作が完了しなかった場合にWithTimeout()でタイムアウト処理を行う ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := srv.Shutdown(ctx); err != nil { log.Fatal("Server Shutdown:", err) } log.Println("Server exiting") } func helloHandler(c *gin.Context) { // テストのため 3 秒待機させる time.Sleep(3 * time.Second) c.String(http.StatusOK, "Welcome Gin Server") }
作成後にGoモジュールの初期化を行います。
% go mod init gin-example go: creating new go.mod: module gin-example go: to add module requirements and sums: go mod tidy
必要なモジュールをインストールしまうs。
% go mod tidy
試す
起動します。
以下のような出力がなされます。
% go run main.go [GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached. [GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production. - using env: export GIN_MODE=release - using code: gin.SetMode(gin.ReleaseMode) [GIN-debug] GET /hello --> main.helloHandler (3 handlers)
別ターミナルでリクエストしてみます。
% curl localhost:8080/hello Welcome Gin Server% # 3秒後に出力される
curl 実行直後にCtrl + Cによる中断を行います。
go run main.go
の出力は以下のように5秒待ってからシャットダウンされました。
[GIN] 2023/04/27 - 16:22:57 | 200 | 10.000212977s | 127.0.0.1 | GET "/hello" ^C2023/04/27 16:22:23 Shutdown Server ... # Ctrl + Cによる中断 2023/04/27 16:22:28 timeout of 5 seconds. 2023/04/27 16:22:28 Server exiting
リクエスト時に10秒待つようにしてみます。
func helloHandler(c *gin.Context) { // テストのため 10 秒待機させる time.Sleep(10 * time.Second) c.String(http.StatusOK, "Welcome Gin Server") }
別ターミナルでリクエストしてみます。
% curl localhost:8080/hello curl: (52) Empty reply from server # 先に中断が実行されるため5秒後に左のような出力がなされる
この場合リクエストが中断されました。
[GIN] 2023/04/27 - 16:22:57 | 200 | 10.000212977s | 127.0.0.1 | GET "/hello" ^C2023/04/27 16:23:09 Shutdown Server ... 2023/04/27 16:23:14 Server Shutdown:context deadline exceeded exit status 1
まとめ
Go の Gin で Graceful shutdown するサンプルを動かしてみました。 net/http でも試してみたいと思います。