コンテンツへスキップ
LatchkeyLatchkey home

CIにおけるretryと冪等性: 副作用なく安全にretryする

不安定なstepのretryが安全なのは、2回実行しても害がない場合だけです。その性質が冪等性であり - どのstepがそれを持つかを知ることが、クリーンな回復と重複したdeployとの分かれ目になります。

retryは一時的なCI障害に対する最もシンプルな対処法ですが、stepに副作用があった場合、盲目的なretryは実害を及ぼしかねません。冪等性はretryを安全にする性質です。

冪等性の意味

ある操作が冪等であるとは、1回実行しても何度実行しても同じ最終状態になることです。npm ci は冪等です - 1回でも3回でも同じ node_modules に収束します。支払いを送信したり行をappendしたりするstepは*冪等ではありません* - 実行のたびに世界が再び変化します。

retryして安全 vs 安全でない

  • 安全: 依存関係のinstall、checkout、読み取り専用のテスト、build。
  • 安全: 冪等になるよう設計されたdeploy(宣言的なapply、upsert)。
  • 安全でない: レコードのappend、通知の送信、カウンタのインクリメント。
  • 安全でない: 実行のたびに新しい外部リソースを作成するあらゆるstep。

stepをretry可能にする

副作用のあるstepは冪等になるよう設計しましょう: 安定したidをキーにしたupsert、命令的なcreateではなく宣言的なapply、そしてAPI呼び出しには冪等性キーを使い、retryされたリクエストがサーバー側で重複排除されるようにします。そうすれば、retryは二重に作用するのではなく再収束します。

ノイズをretryし、シグナルはretryしない

自動retryは、一時的で冪等なstep(ネットワークfetch、依存関係のinstall、既知だが不安定なテスト)に、小さく制限された回数で限定しましょう。非冪等なstepを含むpipeline全体を一律にretryしてはならず、決定論的なロジックの失敗を決してretryしてはいけません - それは本当のバグを隠すだけです。

重要なポイント

  • 冪等 = 複数回実行しても同じ最終状態になる。
  • install、checkout、宣言的なdeployはretryして安全ですが、appendや送信は安全ではありません。
  • upsertと冪等性キーを使って、副作用のあるstepをretry可能にしましょう。
  • retryは一時的で冪等なstepに限定しましょう - 決して本当の失敗を覆い隠さないこと。

よくある質問

What is Retries and idempotency in CI: retry safely without side effects?
Retries are the simplest cure for transient CI failures, but a blind retry can do real damage if the step had side effects. Idempotency is the property that makes retries safe.
What idempotency means?
An operation is idempotent if running it once or many times produces the same end state. npm ci is idempotent - it converges to the same node_modules whether run once or three times. A step that posts a payment or appends a row is *not* - each run changes the world again.
Making steps retry-safe?
Design side-effecting steps to be idempotent: use upserts keyed on a stable id, declarative apply instead of imperative create, and idempotency keys for API calls so a retried request is deduplicated server-side. Then a retry re-converges instead of double-acting.
Retry the noise, not the signal?
Limit automatic retries to transient, idempotent steps (network fetches, dependency installs, flaky-but-known tests) with a small bounded count. Never blanket-retry a whole pipeline that contains non-idempotent steps, and never retry a deterministic logic failure - that just hides a real bug.

関連ガイド