Goのechoフレームワークのグレースフルシャットダウンの実装
記事の内容
Goのechoフレームワークのグレースフルシャットダウンを実装して、実際に処理が中断されないかを実験してみました。
記事を読むと得られるもの
- Goのechoフレームワークのグレースフルシャットダウンの実装方法
対象読者
- echoユーザー
記事の長さ
1分で読めます
グレースフルシャットダウンとは
グレースフルシャットダウンとは、処理の途中でシャットダウンが発生したときに、現在実行中の処理が完了してからシャットダウンを実行するための実装です。
もし、グレースフルシャットダウンが実装されていないと、データベースへの登録・変更・削除処理が中断されて、データ不整合が起こる可能性があります。
echoサーバーを実装する
echoサーバーを実装します。
グレースフルシャットダウンなし
普通に、echoサーバーを実装していきます。公式チュートリアル通りに実装を行うと以下の通りになります。 ( https://echo.labstack.com/docs/quick-start )
package main
import (
"net/http"
"github.com/labstack/echo/v4"
)
func main() {
e := echo.New()
e.GET("/", func(c echo.Context) error {
return c.String(http.StatusOK, "Hello, World!")
})
e.Logger.Fatal(e.Start(":1323"))
}
グレースフルシャットダウンの挙動がわかりやすいように、Sleepを入れて、Webサーバーへアクセスして5秒後にHello, World!
が表示されるようにします。
package main
import (
"net/http"
// この行を追加
"time"
"github.com/labstack/echo/v4"
)
func main() {
e := echo.New()
e.GET("/", func(c echo.Context) error {
// この行を追加
time.Sleep(5 * time.Second)
return c.String(http.StatusOK, "Hello, World!")
})
e.Logger.Fatal(e.Start(":1323"))
}
これで完了です。
以下のコマンドで、echoサーバーを起動し、curlでアクセスします。
$ go run main.go
____ __
/ __/___/ / ___
/ _// __/ _ \/ _ \
/___/\__/_//_/\___/ v4.11.3
High performance, minimalist Go web framework
https://echo.labstack.com
____________________________________O/_______
O\
⇨ http server started on [::]:1323
$ curl localhost:1323
# 5秒待つ
Hello, World!
期待通りの挙動を確認できました。次に、curlでアクセスしている最中にechoサーバーを停止します。
$ curl localhost:1323
# 5秒待っている間に、echoサーバーを停止する
curl: (52) Empty reply from server
サーバーを終了した瞬間に、アクセスができないことを確認しました。
グレースフルシャットダウンが実装されていないため、curlリクエストの最中に処理が中断されてしまいました。
グレースフルシャットダウンあり
グレースフルシャットダウンなしの挙動を確認できたので、次にグレースフルシャットダウンを導入したechoサーバーを実装します。
こちらも、echoのチュートリアル通りに実装します。( https://echo.labstack.com/docs/cookbook/graceful-shutdown )
package main
import (
"context"
"net/http"
"os"
"os/signal"
"time"
"github.com/labstack/echo/v4"
"github.com/labstack/gommon/log"
)
func main() {
// Setup
e := echo.New()
e.Logger.SetLevel(log.INFO)
e.GET("/", func(c echo.Context) error {
time.Sleep(5 * time.Second)
return c.JSON(http.StatusOK, "Hello, World!")
})
// Start server
go func() {
if err := e.Start(":1323"); err != nil && err != http.ErrServerClosed {
e.Logger.Fatal("shutting down the server")
}
}()
// Wait for interrupt signal to gracefully shutdown the server with a timeout of 10 seconds.
// Use a buffered channel to avoid missing signals as recommended for signal.Notify
quit := make(chan os.Signal, 1)
signal.Notify(quit, os.Interrupt)
<-quit
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := e.Shutdown(ctx); err != nil {
e.Logger.Fatal(err)
}
}
上記ファイルを実行します。
$ go run main.go ~/Projects/zenn-go-echo-graceful/graceful
____ __
/ __/___/ / ___
/ _// __/ _ \/ _ \
/___/\__/_//_/\___/ v4.11.3
High performance, minimalist Go web framework
https://echo.labstack.com
____________________________________O/_______
O\
⇨ http server started on [::]:1323
$ curl localhost:1323
# 5秒まつ
"Hello, World!"
期待通りの挙動を確認できました。次に、グレースフルシャットダウンが正常に動作するかどうかを確認するために、curlでリクエスト中にGoサーバーを停止します。
$ curl localhost:1323
# echoサーバーを停止する
"Hello, World!"
curlが完了し、Hello, World!
が表示されてからGoサーバーが停止することを確認できました。
途中処理のリクエストが完了してから、正常終了することを確認できました。
サンプルソース
今回実装したファイルを以下のリポジトリに公開してあります。
note
勉強法やキャリア構築法など、エンジニアに役立つ記事をnoteで配信しています。
Discussion