CLAUDE LABEN
FORK — Claude Code 2.1.212で/forkの挙動が変わりました。会話を新しいバックグラウンドセッションへ複製し、作業を続けたまま並走できます。従来のセッション内サブエージェントは/subtaskに移りましたLIMITS — WebSearchの呼び出しがセッション単位で既定200回に制限されました。サブエージェントの起動も既定200回が上限で、暴走した検索・委譲のループを止められますMCPBG — 2分を超えるMCPツール呼び出しは自動的にバックグラウンドへ移り、セッションが固まらなくなりました。しきい値はCLAUDE_CODE_MCP_AUTO_BACKGROUND_MSで調整できますPLANFIX — プランモードがtouchやrmといったファイルを変更するBashコマンドを、許可プロンプトもcanUseToolコールバックも通さずに実行してしまう不具合が修正されましたSONNET5 — Claude Sonnet 5は導入価格として入力100万トークンあたり2ドル、出力10ドルで提供中です。8月31日を過ぎると3ドルと15ドルに戻りますIPO — Anthropicが早ければ10月の株式公開を視野に、引受銀行が投資家との面談を組み始めたと報じられていますFORK — Claude Code 2.1.212で/forkの挙動が変わりました。会話を新しいバックグラウンドセッションへ複製し、作業を続けたまま並走できます。従来のセッション内サブエージェントは/subtaskに移りましたLIMITS — WebSearchの呼び出しがセッション単位で既定200回に制限されました。サブエージェントの起動も既定200回が上限で、暴走した検索・委譲のループを止められますMCPBG — 2分を超えるMCPツール呼び出しは自動的にバックグラウンドへ移り、セッションが固まらなくなりました。しきい値はCLAUDE_CODE_MCP_AUTO_BACKGROUND_MSで調整できますPLANFIX — プランモードがtouchやrmといったファイルを変更するBashコマンドを、許可プロンプトもcanUseToolコールバックも通さずに実行してしまう不具合が修正されましたSONNET5 — Claude Sonnet 5は導入価格として入力100万トークンあたり2ドル、出力10ドルで提供中です。8月31日を過ぎると3ドルと15ドルに戻りますIPO — Anthropicが早ければ10月の株式公開を視野に、引受銀行が投資家との面談を組み始めたと報じられています
記事一覧/Claude Code
Claude Code/2026-04-23上級

Claude Codeの長時間タスクが途中で止まる問題を、運用設計で根本解決する

Claude Codeで数時間におよぶ長時間タスク——リファクタ、移行、大量テスト生成——を走らせると、途中で止まる・応答が返らない・再開できないという問題に必ず突き当たります。サーキットブレーカー・チェックポイント保存・冪等リトライ・部分成果の退避まで、本番運用で実際に効く設計パターンを具体コード付きでまとめました。

Claude Code197長時間タスクトラブルシューティング37運用設計14レジリエンス3サーキットブレーカー2

Claude Codeで数時間におよぶタスクを走らせる——たとえば500ファイルの一括リファクタ、レガシーコードのTypeScript移行、大量のテスト生成——を任せると、ある確率で途中停止に遭遇します。「12個のファイルを変更し、278個処理したところで止まった。どこまで進んでいて、どこから再開すればいいのかわからない」という状況です。

ここでは同様の長時間タスクを本番運用で走らせている私の経験から、止まっても被害が最小で済み、確実に再開できる運用設計をご紹介します。扱うのは応急処置ではなく、そもそもタスク設計の段階で『止まることを前提にする』という発想の転換です。

長時間タスクが止まる4つの失敗モード

まず原因を切り分けます。Claude Codeの長時間タスクが止まるパターンは、対処が根本的に違う4種類に分類されます。

モード1: 出力トークン・コンテキスト上限

モデルが1回の応答で出せるトークン量、または会話全体で保持できるコンテキスト量に達したケースです。前者は単一応答の途中で切れ、後者はタスクの中盤以降でじわじわ品質が落ち、最終的に「何の作業中だったか忘れる」という症状になります。前者はプロンプト分割で、後者はタスク分割とセッション管理で対処します。

モード2: API側のレート制限・エラー

Anthropic APIのレート制限、一時的な503、あるいはモデル側の内部タイムアウトが返るケースです。Claude Codeはある程度自動リトライしますが、連続失敗が閾値を超えると停止します。これは外部要因なので、リトライ戦略とサーキットブレーカーで扱います。

モード3: ローカル環境の問題

ディスク容量不足、プロセスのメモリ枯渇、シェルセッションの切断、SSHトンネルのタイムアウトなど、ローカル側で起きる停止です。症状としては「Claude Codeが黙り込んだ」に見えますが、実態はローカル環境が先に力尽きています。

モード4: 作業範囲の設計ミス

実は一番多いのがこれです。「1ファイルずつ順に処理して」と頼んだつもりが、Claude Codeが依存関係解決のために何十ファイルも同時に読み込み、早期にコンテキストを使い切る。あるいは「テストも走らせて」と頼んだせいで、各ステップのテスト実行時間がボトルネックになります。タスクの粒度と範囲を設計しなおせば解決します。

本番運用で効くのは、この4つを混同せず、それぞれに別の対処を入れる設計です。

止まることを前提にした「チェックポイント駆動」設計

私が長時間タスクで必ず入れているのが、チェックポイント駆動の進行管理です。基本アイデアは単純で、タスクの進行状況を『Claude Codeの記憶』ではなく『ファイルシステム上のマニフェスト』に書き出すというものです。

最小実装のマニフェスト

作業ディレクトリの直下に、次のようなJSONを置きます。

{
  "task_id": "typescript-migration-2026-04",
  "total_items": 487,
  "completed": [
    { "item": "src/user/profile.js", "finished_at": "2026-04-23T09:12:31Z", "status": "ok" },
    { "item": "src/user/settings.js", "finished_at": "2026-04-23T09:13:02Z", "status": "ok" }
  ],
  "failed": [
    { "item": "src/legacy/auth.js", "reason": "ambiguous imports", "last_tried_at": "2026-04-23T09:15:48Z" }
  ],
  "queued": [
    "src/legacy/rbac.js",
    "src/legacy/session.js"
  ]
}

Claude Codeへの最初のプロンプトで、このマニフェストの仕様と更新ルールを宣言しておきます。「各ファイルの処理を完了した直後に、このJSONを更新してからコミットしてください。途中停止しても、次回起動時に queued の先頭から再開します」と明示するのです。

なぜこれが効くのか

Claude Codeが停止しても、マニフェストはファイルとして残ります。再開時に「このマニフェストを読んで、queuedの先頭から作業を再開してください」と指示するだけで、正確にどこから続きを走らせればいいかが分かります。

重要な設計上のポイントが2つあります。1つ目、各アイテムの処理が成功したら即座にマニフェストを更新すること。5ファイルまとめて更新すると、4ファイル目で停止した時に進捗が巻き戻ります。2つ目、更新をgit commitに紐付けること。万が一マニフェストが破損しても、直前のコミットから復旧できます。

実装スニペット(Bash ラッパー)

私は次のようなラッパーを使っています。Claude Codeが各アイテムの処理後に呼び出す想定です。

#!/usr/bin/env bash
# mark_done.sh — マニフェストを1件分更新してコミット
set -euo pipefail
 
MANIFEST="./task_manifest.json"
ITEM="$1"
STATUS="${2:-ok}"
 
python3 - "$MANIFEST" "$ITEM" "$STATUS" << 'PY'
import sys, json, datetime
manifest_path, item, status = sys.argv[1], sys.argv[2], sys.argv[3]
with open(manifest_path) as f:
    m = json.load(f)
m["completed"].append({
    "item": item,
    "finished_at": datetime.datetime.utcnow().isoformat() + "Z",
    "status": status
})
if item in m["queued"]:
    m["queued"].remove(item)
with open(manifest_path, "w") as f:
    json.dump(m, f, indent=2, ensure_ascii=False)
PY
 
git add "$MANIFEST"
git commit -m "progress: $ITEM ($STATUS)" --quiet

各処理成功時に ./mark_done.sh src/user/profile.js を実行するだけで、進捗がコミット履歴に一行ずつ刻まれていきます。止まった後でも git log でどこまで進んだかが一目で分かります。

サーキットブレーカーの最小設計

連続失敗が続く時に、何度でもリトライしてAPIコストを溶かしてしまう事故を防ぐのがサーキットブレーカーです。ソフトウェア工学でよく使われるパターンですが、Claude Codeの運用にもそのまま使えます。

状態機械の設計

3つの状態を持たせます。

  • Closed(通常運転): 失敗が閾値未満なら、リトライし続ける
  • Open(回路遮断): 連続失敗が閾値を超えたら、一定時間まったく試行しない
  • Half-Open(様子見): Openの冷却期間が終わったら、1件だけ試す。成功すればCloseに戻り、失敗すればOpenに戻る

実装例

import time, json, pathlib
 
STATE_PATH = pathlib.Path("./cb_state.json")
THRESHOLD = 3            # 連続失敗許容数
COOLDOWN_SEC = 600       # Open状態での待機秒数
 
def load_state():
    if not STATE_PATH.exists():
        return {"state": "closed", "fail_count": 0, "opened_at": 0}
    return json.loads(STATE_PATH.read_text())
 
def save_state(s):
    STATE_PATH.write_text(json.dumps(s, indent=2))
 
def allow_call():
    s = load_state()
    if s["state"] == "closed":
        return True
    if s["state"] == "open":
        if time.time() - s["opened_at"] >= COOLDOWN_SEC:
            s["state"] = "half_open"
            save_state(s)
            return True
        return False
    if s["state"] == "half_open":
        return True
    return False
 
def record_success():
    save_state({"state": "closed", "fail_count": 0, "opened_at": 0})
 
def record_failure():
    s = load_state()
    s["fail_count"] += 1
    if s["fail_count"] >= THRESHOLD:
        s["state"] = "open"
        s["opened_at"] = time.time()
    save_state(s)

Claude Codeから呼ぶ処理の前後で allow_call()record_success()record_failure() をフックするだけです。閾値3・冷却10分という設定は保守的で、一時的な503程度なら自動で回復しつつ、本格的な障害時には無駄なAPI消費を止めてくれます。

冪等リトライを前提にした作業粒度

サーキットブレーカーが働いた後の再開で事故を防ぐには、各作業が冪等(同じ操作を何度繰り返しても結果が同じ)であることが必須です。リファクタ1件の再実行で結果が壊れるなら、そもそも再開戦略が成立しません。

冪等にするための3つの設計ルール

1つ目は作業前に現在状態を確認することです。「ファイルをTypeScript化する」なら、まず拡張子とimport文から既に移行済みかを判定し、済みならスキップします。マニフェストの completed だけを信用すると、マニフェスト更新後・コミット前に停止した場合に二重処理が起きます。

2つ目は出力を一意なパスに書くことです。ログ・中間成果物は logs/{task_id}/{item}_{attempt}.log のように、試行番号まで含めた一意パスにします。同じパスを上書きすると、再実行時に前回の失敗原因を追えなくなります。

3つ目は共有リソースの変更は最後にまとめることです。DBマイグレーション、APIキーの発行、外部サービスへの通知など、冪等にしにくい操作は、全件処理が終わった後の「確定フェーズ」に集約します。途中停止時に中途半端な状態を残さない鉄則です。

部分成果を退避するプロトコル

「途中まで進んだ成果」を失わないために、停止が検知されたら即座に状態を凍結します。

停止検知のトリガー

Claude Codeの応答が20分以上来ない、あるいはサーキットブレーカーがOpen状態に入ったら、次のコマンドを自動実行するフックを仕込みます。

#!/usr/bin/env bash
# freeze.sh — 作業中の状態を退避ブランチに保存
set -euo pipefail
 
TASK_ID=$(python3 -c "import json; print(json.load(open('task_manifest.json'))['task_id'])")
FREEZE_BRANCH="freeze/${TASK_ID}-$(date +%Y%m%d-%H%M%S)"
 
git checkout -b "$FREEZE_BRANCH"
git add -A
git commit -m "freeze: ${TASK_ID} at $(date -Iseconds)" --allow-empty
git push origin "$FREEZE_BRANCH"
echo "Frozen to $FREEZE_BRANCH"

退避ブランチは本線にマージせず、freeze/* として分離しておきます。再開時にマニフェストと照合して問題なければ本線へrebase、問題があれば退避ブランチの成果を捨てて、マニフェストの queued から再スタートします。

失敗通知と合わせる

停止を人間が後で気付くのでは遅すぎます。サーキットブレーカーがOpenに入った時点で、Slack・Discord・メールのいずれかに通知を飛ばすフックを入れます。最小実装は次のようにシンプルで十分です。

curl -X POST -H 'Content-Type: application/json' \
  -d "{\"text\": \"⛔ CB opened on ${TASK_ID}. Check freeze/${TASK_ID}-*.\"}" \
  "$SLACK_WEBHOOK_URL"

タスク設計の段階で入れるべき「止まる前提」

最後に、設計の発想そのものを切り替える話をします。長時間タスクを組むとき、私は次のチェックリストを必ず通すようにしています。

  • ひとつの作業単位は30秒〜5分以内に収まるか: 大きすぎる単位は、失敗時のコストが跳ね上がる
  • 作業単位は冪等か、または実行前の状態チェックで冪等化できるか: できないなら粒度を変える
  • 進捗はマニフェストに残るか: 残らないなら、再開戦略が存在しない
  • 失敗時の通知経路はあるか: ないなら、止まったことに何時間も気付かない
  • サーキットブレーカーの閾値・冷却時間は明示されているか: 暗黙値だと、暴走時の被害が予測不能

この5項目がすべて「はい」と言えるタスクだけをClaude Codeに渡す、というルールにすると、本番で止まっても慌てない運用ができるようになります。

全体を振り返ってに代えて — 最初の一歩

この記事の内容を全部いっぺんに導入するのは大変です。明日からの一歩としておすすめしたいのは、マニフェスト駆動だけを試してみることです。

JSONファイル1個と、成功時にそれを更新してコミットするBashラッパー1個。それだけで、長時間タスクの『今どこまで進んでいるか』がgit logに残り、止まっても冷静に再開できるようになります。サーキットブレーカーや退避プロトコルは、マニフェスト駆動が回り始めてから段階的に足せば十分です。

長時間タスクの失敗は避けられませんが、失敗の被害は設計で十分に抑え込めます。ぜひ、次の大きなタスクから一つずつ組み込んでみてください。

シェア

お読みいただきありがとうございます

Claude Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

Claude Code2026-07-16
夜間セッションの常駐メモリが朝には数GB — 蓄積の四つの出どころと、RSS を刻んで切り分ける
夜間に回した Claude Code のプロセスを朝に見ると、常駐メモリが数GBまで膨らんでいました。2.1.209 で塞がれた四つの蓄積源と、自分の構成に残る分を RSS の傾きで切り分ける方法、しきい値で畳む運用までを個人開発の目線で整理します。
Claude Code2026-07-01
Claude Code をアップデートしたら hook が発火しなくなった — ハイフン入り matcher の厳密一致化(v2.1.195)
Claude Code v2.1.195 でハイフンを含む hook matcher が部分一致から厳密一致に変わり、既存の PreToolUse フックが静かに発火しなくなりました。原因の切り分けと、壊れない matcher の書き方をまとめます。
Claude Code2026-06-27
無人で回し続けても重くならないか — Claude Code 長時間セッションのメモリ使用量を観測して頭打ちにする
長時間の無人セッションで Claude Code が徐々に重くなる問題を、ps による RSS 定点観測・ローリング基準値のウォッチドッグ・セグメント分割の3点で頭打ちにする運用設計を、観測スクリプトと before/after で具体的にまとめます。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →