グレースフルシャットダウン

処理中のリクエストを完了させてからプロセスを安全に停止する終了手法

運用可用性

グレースフルシャットダウンとは

グレースフルシャットダウン (Graceful Shutdown) は、プロセスの停止要求 (SIGTERM) を受けた際に、処理中のリクエストを完了させ、リソース (DB 接続、ファイルハンドル) を適切に解放してから安全に終了する手法である。即座に kill (SIGKILL) すると、処理中のリクエストが中断され、データの不整合やユーザーへのエラーが発生する。

Node.js での実装

const server = app.listen(3000);

process.on('SIGTERM', () => {
  console.log('SIGTERM received. Shutting down gracefully...');

  // 1. 新しいリクエストの受付を停止
  server.close(async () => {
    console.log('All connections closed');

    // 2. DB 接続を解放
    await db.end();

    // 3. プロセスを終了
    process.exit(0);
  });

  // 4. タイムアウト: 30秒以内に終了しなければ強制終了
  setTimeout(() => {
    console.error('Forced shutdown after timeout');
    process.exit(1);
  }, 30000);
});

SIGTERM と SIGKILL の違い

シグナル 動作 キャッチ可能
SIGTERM 終了要求 (グレースフルシャットダウンの機会) はい
SIGKILL 即座に強制終了 いいえ

Kubernetes や ECS は、まず SIGTERM を送り、一定時間後に SIGKILL を送る。SIGTERM をハンドリングしないと、SIGKILL で強制終了される。

Kubernetes での設定

spec:
  terminationGracePeriodSeconds: 30  # SIGTERM → SIGKILL の猶予時間
  containers:
    - name: app
      lifecycle:
        preStop:
          exec:
            command: ["sh", "-c", "sleep 5"]  # LB からの除外を待つ

Pod の停止フロー:

1. Kubernetes が Pod を "Terminating" に設定
2. Service のエンドポイントから除外 (新規リクエスト停止)
3. preStop フックを実行 (sleep 5: LB の反映を待つ)
4. SIGTERM を送信
5. アプリが処理中リクエストを完了
6. terminationGracePeriodSeconds 後に SIGKILL

preStopsleep 5 は重要だ。Service のエンドポイント除外と SIGTERM の送信は並行して行われるため、SIGTERM を受けた直後にまだ新しいリクエストが来る可能性がある。

ECS / Fargate での設定

{
  "stopTimeout": 30,
  "essential": true
}

ECS は stopTimeout 秒後に SIGKILL を送る。ALB の Deregistration Delay と合わせて設定する。

Lambda でのグレースフルシャットダウン

Lambda はリクエスト単位で実行されるため、通常のグレースフルシャットダウンは不要だ。ただし、Lambda Extensions を使う場合は SIGTERM ハンドラーでクリーンアップ処理を行う。

グレースフルシャットダウンの比較

環境 シグナル 猶予時間 対応
ECS Fargate SIGTERM 30 秒 (設定可能) プロセスで SIGTERM をハンドル
Kubernetes SIGTERM 30 秒 (terminationGracePeriodSeconds) preStop フック
Lambda - 不要 (リクエスト単位) ハンドラの完了を待つ
EC2 (ASG) Lifecycle Hook 設定可能 フックで処理完了を通知

実践的な知識は関連書籍でも得られる。

関連用語