`--lock-wait` オプションでデプロイロック取得をリトライ可能に

basecamp/kamal

--lock-wait を導入することで、CI ワークフローが同一のデプロイロックを争う際に即座に失敗せず、指定した時間までポーリングでロック取得を待機できるようになりました。これにより共有 CI 環境でのデプロイ安定性が向上します。

背景

CI 環境で複数のジョブが同時にデプロイを実行しようとすると、デプロイロック が競合し、最初に取得したジョブ以外は LockError で即座に中止されます。(総論)

現在の実装はロック取得の mkdir を単一の原子操作として行い、ロックが既に存在すれば例外をスローするだけです。この挙動は単体のデプロイでは問題ありませんが、同時走行が前提のパイプラインではジョブ全体が失敗する原因となります。(各論)

そのため、ロックが解放されるまで待機し、タイムアウトまでに取得できれば処理を続行できるメカニズムが求められました。(結論)

技術的な変更

Kamal::Cli::Base に 3 つの新しい class_option が追加され、--lock-wait 系のフラグとタイムアウト・ポーリング間隔を設定できるようになりました。(総論)

+    class_option :lock_wait, type: :boolean, default: false, desc: "Wait for the deploy lock if it's already held instead of failing immediately"
+    class_option :lock_wait_timeout, type: :numeric, default: 900, desc: "Maximum seconds to wait for the deploy lock when --lock-wait is set"
+    class_option :lock_wait_interval, type: :numeric, default: 15, desc: "Seconds between deploy lock polls when --lock-wait is set"

これにより CLI の呼び出し側は kamal deploy --lock-wait のようにシンプルに指定でき、デフォルトで 15 分間、15 秒ごとに再試行します。(各論)

Kamal::Commander でも同様の属性が追加され、reset メソッドでデフォルト値が初期化されます。(各論)

-  attr_accessor :verbosity, :holding_lock, :connected, :logging
+  attr_accessor :verbosity, :holding_lock, :connected, :logging, :lock_wait, :lock_wait_timeout, :lock_wait_interval
@@
-    self.logging = false
+    self.logging = false
+    self.lock_wait = false
+    self.lock_wait_timeout = 900
+    self.lock_wait_interval = 15

Kamal::Cli::Base#acquire_lock では、KAMAL.lock_wait が真の場合に新設した acquire_lock_with_wait を呼び出す分岐が追加されました。(総論)

@@
-        raise_if_locked do
-          say "Acquiring the deploy lock...", :magenta
-          on(KAMAL.primary_host) { execute *KAMAL.lock.acquire("Automatic deploy lock", KAMAL.config.version), verbosity: :debug }
-        end
+        if KAMAL.lock_wait
+          acquire_lock_with_wait
+        else
+          raise_if_locked do
+            say "Acquiring the deploy lock...", :magenta
+            execute_lock_acquire(AUTOMATIC_DEPLOY_LOCK_MESSAGE)
+          end
+        end

acquire_lock_with_wait はロック取得が失敗した際に capture_lock_status でロック情報を出力し、設定された間隔で再度 mkdir を試行します。タイムアウトか手動でロック保持されている場合は Kamal::Cli::LockError が送出されます。(各論)

ロック取得ロジック自体は既存のコードパスを変更せず、--lock-wait が無効な場合は従来通り即座に例外をスローします。これにより既存ユーザーへの後方互換性が保たれます。(結論)

設計判断

ロック待機機構は新規コマンドではなく、既存のロック取得フローに組み込む方針が採用されました。(総論)

同じ mkdir の原子操作を再利用することで、待機中に別プロセスがロックを取得するレースコンディションを回避し、追加のチェック段階を不要にしています。(各論)

CLI オプションは Kamal::Cli::Base に直接追加し、Kamal::Commander に属性を持たせることで、全コマンドで一貫したフラグ扱いが可能になりました。デフォルトは false のままで、従来の動作を変えることはありません。(各論)

新たに LockHeldErrorLockMissingError が定義され、lib/kamal/cli/lock.rb 内でロックが存在しないケースを明示的に捕捉しています。これによりエラーメッセージが統一され、テストでも容易にシミュレートできます。(各論)

以上の設計は、CI 環境でのデプロイ競合を緩和しつつ、既存フローへの侵入を最小限に抑えるトレードオフを選択した結果と言えます。(結論)

まとめ

--lock-wait オプションは、デプロイロック取得失敗時に待機リトライを行うことで、共有 CI パイプラインにおけるデプロイ失敗を減少させます。オプションはデフォルトで無効なため既存利用者への影響はなく、必要に応じてタイムアウトとポーリング間隔を調整可能です。

記事メタデータ

Generated by:
gpt-oss-120b for DiffDaily
LLM Trace:
5823bb0f

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

品質レビュー結果

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

Review Criteria:

記事構成 ✓ PASS

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

リード文、背景(Context)、技術的な変更(Technical Detail)、設計判断(任意)、まとめ(結論)の全要素が揃っており、総論→各論→結論の流れが明確です。

カスタムMarkdown構文 ✓ PASS

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

コードブロックは `言語:ファイルパス` 形式で正しく記述され、PRリンクも適切にマークダウン化されています。

対象読者への適合性 ✓ PASS

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

内容はエンジニア向けで、専門用語や実装詳細が中心です。初心者向けの余計な説明はありません。

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

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

各セクションは総論・各論・結論のパラグラフ構成になっており、1文目がトピックセンテンス、1段落1トピック、段落長も適切です。

Diff内容との照合 ✓ PASS

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

記事中のコードブロックは提供されたDiffと一致し、追加・変更箇所が正確に反映されています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

用語はPRやDiffで使用されているものと一致し、誤用は見られません。

説明の技術的正確性 ✓ PASS

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

技術的な説明はPRの記述と矛盾せず、デフォルト値や動作概要が正確に伝えられています。

事実の突合 ✓ PASS

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

全ての主張がPRタイトル・説明・Diffで裏付けられており、捏造や推測はありません。

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

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

数値(タイムアウト900秒=15分、ポーリング15秒、PR番号#1844など)は正確です。

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

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

記事タイトルはPRタイトルの意味を日本語で的確に表現しています。

外部知識の正確性 ✓ PASS

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

バージョンサポートやリリース日程等の外部情報は含まれていません。

時間表現の正確性 ✓ PASS

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

時間表現はPRのデフォルト設定と一致しており、歪曲はありません。