stop_timeout オプションで Docker 停止タイムアウトを柔軟に設定

basecamp/kamal

kamal の停止処理は、proxynon‑proxy のロールによってデフォルトのタイムアウトが異なります。この PR は、そのタイムアウトを明示的に制御できる stop_timeout オプションを導入し、ロール単位・全体単位で上書き可能にします。

背景

既存の停止ロジックは drain_timeout を流用しており、proxy ロールでは Docker のデフォルト 10 秒、non‑proxy ロールでは drain_timeout(デフォルト 30 秒)が適用されていました。この設計では、同一コンテナ内に proxy と non‑proxy の両方をデプロイした場合、non‑proxy ロールが 10 秒のタイムアウトで停止されるリスクがあります。

この問題を解消するために、停止時のタイムアウトを個別に設定できるオプションが必要となり、本 PR で stop_timeout が追加されました。

技術的な変更

stop_timeout の設定取得メソッドが lib/kamal/configuration.rb に追加され、raw_config.stop_timeout を返すようになりました。

@@
   def drain_timeout
     raw_config.drain_timeout || 30
   end

+  def stop_timeout
+    raw_config.stop_timeout
+  end

設定ドキュメント (lib/kamal/configuration/docs/configuration.yml) に stop_timeout の説明が追記され、非 proxy ロールは drain_timeout、proxy ロールは 10 秒がデフォルトと明記されました。

@@
 # How long to wait for a container to drain, default 30:
 drain_timeout: 10

+# Stop timeout
+#
+# How long to wait for a container to stop after SIGTERM, default is
+# the drain_timeout for non-proxied roles and 10s (Docker default) for proxied roles.
+# Can be overridden per role:
+stop_timeout: 30

ロール単位でのオーバーライド例が lib/kamal/configuration/docs/role.yml に追加され、stop_timeout キーが使用できることを示しています。

@@
   cmd: "bin/jobs"
+  stop_timeout: 30
   options:
     memory: 2g

lib/kamal/configuration/role.rbstop_args が改修され、stop_timeout が存在すればそれを直接使用し、無ければ従来のロジック(proxy なら nil、非 proxy なら config.drain_timeout)をフォールバックします。また、ロール固有の stop_timeout を取得するヘルパー stop_timeout が追加されました。

@@
-    timeout = running_proxy? ? nil : config.drain_timeout
+    timeout = stop_timeout || (running_proxy? ? nil : config.drain_timeout)
@@
   def stop_args
@@
   end
+
+  def stop_timeout
+    specializations["stop_timeout"] || config.stop_timeout
+  end

テストスイートにも新機能を検証するケースが加えられ、stop_timeout が正しくコマンド文字列や引数へ反映されることを確認しています(test/commands/app_test.rbtest/configuration/role_test.rb)。

設計判断

stop_timeoutグローバル設定 + ロール固有設定 の二層構造で導入され、既存の設定階層 (raw_configspecializations) と整合性を保ちました。この設計により、既存ロジックへの侵入は最小限に抑えつつ、柔軟な上書きが可能です。

デフォルト値は proxy ロールは Docker のデフォルト 10 秒、非 proxy ロールは drain_timeout とし、既存ユーザーへの影響を避けています。新たに stop_timeout を明示的に設定しない限り、従来通りの挙動が維持されます。

まとめ

stop_timeout オプションの追加により、kamal の停止処理はロール単位・全体単位で細かくチューニングできるようになりました。デフォルトは従来と同様の安全な挙動を保ちつつ、同一コンテナ内での proxy / non‑proxy 混在環境でも適切なタイムアウトを設定できる点が大きな利点です。

記事メタデータ

Generated by:
gpt-oss-120b for DiffDaily
LLM Trace:
4dacc9ba

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
gpt-oss-120b for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

リード文がタイトル直下にあり、背景・技術的変更・設計判断・まとめの各セクションが揃っているため、総論→各論→結論の構成が適切です。

カスタムMarkdown構文 ⚠ WARNING

シンタックスハイライト・GitHubリンク記法の正確性

コードブロックは `言語:ファイルパス` の形式で正しく記述されている。PRリンクは `[PR #1813](URL)` と記載されており、要件の `[#123](URL)` 形式から外れているため警告です。コミットIDのリンクは記載されていませんが、必須ではありません。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

対象は `kamal` の設定に精通したエンジニアで、専門用語中心の記述となっており、初心者向けの過度な説明はありません。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションは総論パラグラフ・各論パラグラフ・結論パラグラフで構成され、段落はトピックセンテンスで始まり 1 段落 1 トピック、長さも適切に分割されています。空行で区切りも保持されています。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

記事中のコードブロックは提供された Diff と完全に一致しており、ファイル名・変更内容ともに合致しています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

`stop_timeout`、`drain_timeout`、`proxy` などの用語は PR 内容と一致し、誤用は見られません。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

技術的な説明は Diff と PR の記述に基づいており、因果関係も正しく述べられています。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

記事のすべての主張は PR のタイトル、説明、Diff で裏付けられており、外部知識や根拠のない数値・予測は含まれていません。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

デフォルトの秒数(10 秒、30 秒)や `stop_timeout: 30` などの数値は Diff と一致しています。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事タイトルは PR の機能(stop_timeout オプションの追加)を正確に表現しています。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

LTS、リリース日程等の外部知識は記載されていません。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

時間表現に関する記述は PR と一致しており、歪曲はありません。