GracefulShutdownとは
ざっくりいうとアプリ停止の際に安全に正常終了する仕組みのこと。
リクエストの受付を停止して、処理中のプロセスが完全に終わるまで待ってからアプリを終了する。
リリースの際のデプロイ、Kubernetesのローリングアップデートの場面等で活用。
Spring Boot 2.3以降、GracefulShutdownが公式で追加された。
Graceful shutdown is supported with all four embedded web servers (Jetty, Reactor Netty, Tomcat, and Undertow) and with both reactive and Servlet-based web applications. When a grace period is configured, upon shutdown, the web server will no longer permit new requests and will wait for up to the grace period for active requests to complete.
公式リファレンス
Tomcat利用する場合はバージョン9.0.33以降が必要。
設定
application.ymlに以下を追加
server:
shutdown: graceful
spring:
lifecycle:
timeout-per-shutdown-phase: 20s #停止までの猶予期間。デフォルトは30s。
検証
検証用にヘルスチェックにスリープ処理(重い処理の再現)を入れる。
Thread.sleep(10*1000L);
上記ヘルスチェックのエンドポイントリクエスト中にシャットダウン。
(今回はactuatorの機能で終了させたけどkubectlコマンドでもいいと思う)
# コンテナに入る
$ kubectl exec -it ポッド名 -c コンテナ名 -- /bin/bash
# シャットダウン
$ curl -X POST localhost:9090/actuator/shutdown
{"message":"Shutting down, bye..."}
bash-4.2# command terminated with exit code 137 # コンテナから追い出された
# pod確認 → 再起動されてる
$ kubectl get pods
my-pod 2/2 Running 1 (4m50s ago) 67m
ヘルスチェックも時間経過後、問題なくレスポンスが返る。
{"status":"UP"}
ちなみにGracefulShutdownを使用しない状態で同じことをやると502エラーが返る。
502 Bad Gateway
参考