Claude Media
Claude CodeでCloud Tasksのキューを設計する — 再試行・レート制限・重複排除

Claude CodeでCloud Tasksのキューを設計する — 再試行・レート制限・重複排除

gcloudの参照系だけを許可し、変更系は確認付きにして、Cloud Tasksの再試行・レート制限・タスク名による重複排除をClaude Codeと設計する手順です。

Cloud Tasksのキュー設定は、値の組み合わせで挙動が決まります。再試行の回数と間隔、ディスパッチの速さ、タスク名の付け方が絡み合い、1か所を変えると他の前提が崩れます。Claude Codeに任せるなら、まず触ってよいコマンドを絞ります。参照系は自由に、変更系は確認付きに、破壊系は拒否に分けると、設計の相談と実行を安全に分けられます。

この記事では、gcloud tasks の権限を3段に分ける設定と、キューの3つの設定面(レート制限・再試行・重複排除)を設計する流れを示します。

gcloud tasksを3段に分けて許可する

Claude Codeの権限ルールは、deny、ask、allowの順に評価され、最初に当たったものが結果を決めます。広いdenyの内側に狭いallowで穴を開けることはできません。この性質に合わせて、コマンドを次のように分けます。

段対象コマンド扱い
参照対象コマンドgcloud tasks queues describe / gcloud tasks queues list / gcloud tasks list扱いallow
変更対象コマンドgcloud tasks queues create / update / pause / resume扱いask
破壊対象コマンドgcloud tasks queues delete / purge扱いdeny

.claude/settings.json に書くと、次の形になります。

{
  "permissions": {
    "allow": [
      "Bash(gcloud tasks queues describe *)",
      "Bash(gcloud tasks queues list *)",
      "Bash(gcloud tasks list *)"
    ],
    "ask": [
      "Bash(gcloud tasks queues create *)",
      "Bash(gcloud tasks queues update *)",
      "Bash(gcloud tasks queues pause *)",
      "Bash(gcloud tasks queues resume *)"
    ],
    "deny": [
      "Bash(gcloud tasks queues delete *)",
      "Bash(gcloud tasks queues purge *)"
    ]
  }
}

* はサブコマンドの後ろに置いています。Bash(gcloud tasks queues describe *) は describe だけを通し、update は通しません。末尾の * は、半角スペースを挟めば引数なしの形にも当たります。

gcloud は組み込みの読み取り専用コマンド一覧に入っていないため、参照系にもallowが要ります。一覧に入っているのは ls や cat、git の読み取り形などです。

denyだけでは守りきれない書き方がある

権限ルールが照合するのは、Claudeが書いたコマンド文字列です。/usr/bin/gcloud tasks queues purge q や sh -c 'gcloud tasks queues purge q' のような別の書き方は、denyに当たりません。purge はキューの全タスクを削除する操作で、取り消せません。公式のリファレンスにも、purgeは取り消せないと書かれています。

守りを固めるなら、次のどれかを重ねます。

  • 実行するサービスアカウントに、purge と delete を含む権限を与えない
  • PreToolUseフックでコマンド全文を検査する
  • サンドボックスでネットワークとファイルの範囲を絞る

IAMの絞り方はGoogle CloudのMCPサーバーをIAMで権限制御するに、gcloudをMCPサーバー経由で使う方法はgcloud MCPサーバーをClaude Codeに追加してGoogle Cloudを操作するにあります。

レート制限はトークンバケットで決まる

Cloud Tasksのディスパッチ速度は、キューごとのトークンバケットで制御されます。タスクを1つ実行するたびにバケットからトークンが減り、max_dispatches_per_second の速さで補充されます。同時に動くタスク数の上限が max_concurrent_dispatches です。

設定は gcloud tasks queues update で行います。

gcloud tasks queues update my-queue \
    --location=asia-northeast1 \
    --max-dispatches-per-second=50 \
    --max-concurrent-dispatches=20

max_burst_size はAPIで設定する値ではなく、max_dispatches_per_second からシステムが計算します。queue.yaml を使うと bucket_size として手で決められますが、同じキューにAPIと queue.yaml の両方を使うことは推奨されていません。どちらか一方に統一します。

もう1つ注意したいのが、負荷が不均一なときのバーストです。バケットにトークンが溜まっていると、実際のディスパッチ速度が設定値を超える場合があります。送信先が遅いサービスだと、HTTP 429や503が返る原因になります。公式は、レートが遅いときに max_concurrent_dispatches を小さくする方法を挙げています。

上限値は先にClaudeへ渡しておく

設計相談の前に、キューの上限を伝えておくと提案がぶれません。公式の上限表から、設計に効くものを抜き出します。

数字

Cloud Tasksの上限値

  • キューのディスパッチ速度

    500/秒

    1キューあたり。超えるなら複数キュー

  • タスクサイズ

    1 MiB

    1タスクの上限

  • 最大保持期間

    31日

    追加から自動削除まで

  • 重複排除の窓

    最大24時間

    削除後も同名を拒否

quotasページの表より

再試行は4つの数字で形が決まる

失敗したタスクは、指数バックオフで再試行されます。設定する値は5つですが、動きを決めるのは次の関係です。

gcloud tasks queues update my-queue \
    --location=asia-northeast1 \
    --max-attempts=8 \
    --max-retry-duration=3600s \
    --min-backoff=10s \
    --max-backoff=300s \
    --max-doublings=3

--max-doublings=3 のとき、再試行の間隔は最小値から3回倍になり、その後は直線的に増え、最後は最大値で頭打ちになります。公式の例(最小10秒、最大300秒、倍増3回)では、間隔は10秒、20秒、40秒、80秒、160秒、240秒、300秒、300秒と続きます。

終わり方には2つの条件が絡みます。--max-attempts に -1、--max-retry-duration に 0s を指定すると、どちらも無制限になります。このときタスクは最大保持期間まで再試行を続けます。それ以外の組み合わせでは、試行回数と継続時間の両方が満たされた時点で再試行が止まり、タスクは削除されます。

Claudeに設計を頼むときは、この2条件の関係を明示します。「回数だけ決めて、継続時間を0sにした」設定は、意図せず保持期間いっぱいまで再試行する設定とは別物だからです。再試行を受ける側の実装は、Sidekiqジョブの冪等性と同じく、同じタスクが複数回届く前提で書きます。

タスク名による重複排除の落とし穴

タスクに名前を付けると、Cloud Tasksはその名前で重複排除を行えます。ただし公式は、この処理に伴ってレイテンシが増える場合があると書いています。gcloud tasks create-http-task のリファレンスでも、重複の名前を調べる追加コストがあるため、IDを指定しない場合はシステムがランダムな一意のIDを割り当てるとされています。

注意が要るのは、削除したあとの扱いです。

  • 成功して消えたタスクと同じ名前でタスクを追加すると、最大24時間は拒否される
  • 同名のキューも、削除してから3日間は作り直せない
  • タスクの最大スケジュール先は現在から30日後まで

つまり「同じ名前で再投入して再実行する」運用は、24時間以内だとエラーになります。再実行用には別名を付けるか、名前に実行回の識別子を含めます。名前の候補を決めるときは、ドメイン側の一意キー(注文IDなど)に再実行の番号を足す形がわかりやすいでしょう。

名前の設計をClaudeに点検させる

名前の規則は、Claudeにテストケースを書かせると穴が見つかります。たとえば次のような依頼です。

タスク名は "order-{orderId}-r{retry}" の形にします。
24時間の重複排除窓を踏まえて、次の3ケースで衝突するか表にしてください。
1. 同じ注文を5分後に再投入
2. 同じ注文を2日後に再投入
3. retry番号だけ増やして再投入

窓の長さを前提に含めておくと、表の根拠がずれません。冪等性そのものの設計は、受信側の問題としてStripe webhookの冪等受信の考え方が使えます。

変更前に参照して、変更後にも参照する

変更系を ask に置くと、毎回確認が出ます。この確認を形だけにしないために、手順を決めておきます。

手順

キュー設定を変えるときの流れ

  1. 1

    現状を取得する

    gcloud tasks queues describe my-queue --location=asia-northeast1 を実行させ、rateLimits と retryConfig を読み取らせます。参照系なので確認は出ません。

  2. 2

    変更案をdiffで示させる

    現状値と変更後の値を並べた差分を、コマンドと一緒に出させます。ここで上限表(500/秒など)と矛盾していないかを見ます。

  3. 3

    updateを承認して実行する

    ask のプロンプトで、コマンドが差分と一致していることを確かめてから承認します。

  4. 4

    もう一度describeで確かめる

    公式も、設定後に describe で確認するよう案内しています。出力に、設定した値が入っているかを突き合わせます。

describe の出力は、次のような形です。値は公式ドキュメントの例に沿ったものです。

name: projects/PROJECT_ID/locations/LOCATION_ID/queues/QUEUE_ID
rateLimits:
  maxBurstSize: 100
  maxConcurrentDispatches: 1000
  maxDispatchesPerSecond: 500.0
retryConfig:
  maxAttempts: 100
  maxBackoff: 3600s
  maxDoublings: 16
  minBackoff: 0.100s
state: RUNNING

ルーティングを上書きする場合だけは、順序が違います。既存キューにキューレベルのルーティングを適用するときは、先にキューを一時停止し、適用後に1分待ってから再開します。新しい設定が反映されるまで最大1分かかり、待たずに再開すると古い設定でタスクが送られることがあるためです。pause と resume が ask にあるのはそのためで、手順の途中で確認が出るのは想定どおりです。なお、CMEK(顧客管理の暗号鍵)を有効にしたキューでは、キューレベルのルーティングが使えません。

CLAUDE.mdに書いておくこと

権限ルールは操作を止めるだけで、設計の方針は伝えません。方針は CLAUDE.md に短く書いておきます。

## Cloud Tasks
- キューの変更は describe で現状を取得してから提案する
- 再試行は max-attempts と max-retry-duration の両方を明記する
- タスク名は重複排除の窓(最大24時間)を前提に決める
- delete と purge は実行しない。必要なら手順だけ示す

この記述は、Claudeが取りうる行動を方向づけるものです。強制力はないため、denyルールと組み合わせて使います。

Pub/Subとの使い分け

同じGoogle Cloudの非同期基盤でも、Pub/Subは配信の仕組みで、Cloud Tasksは個々のタスクの実行を制御する仕組みです。タスク単位でレート、再試行、スケジュール、名前による重複排除を扱いたいときにCloud Tasksが向きます。Pub/Sub側の接続はPub/SubのリモートMCPサーバーをClaude Codeにつなぐ手順にまとめています。

まとめ

gcloud tasks を参照・変更・破壊の3段に分けると、Claude Codeに設計を相談しながら、実行の主導権を手元に残せます。キューの3つの設定面は、トークンバケットによる速度、2条件で終わる再試行、24時間残る重複排除の窓です。

押さえる点は2つです。再試行を無制限にしたいのでなければ、回数と継続時間の両方を決めること。同じ名前の再投入は24時間以内なら拒否されるため、名前に再実行の識別子を含めること。denyは書き方の違いをすり抜けられるので、purge相当の権限は、サービスアカウント側でも外しておく構成が堅実です。

参照した一次ソース

この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。

  1. code.claude.com/docs/en/permissions
  2. cloud.google.com/tasks/docs/configuring-queues
  3. cloud.google.com/tasks/docs/quotas
  4. cloud.google.com/sdk/gcloud/reference/tasks/queues/purge
この記事を共有:XはてブLinkedIn