◉CLAUDE LABEN
●2.1.301 — vim の % モーション、VS Code パネルでの LaTeX 数式表示、使用量上限待ちのリトライ監視の上限が入りました(10/15)●2.1.299 — 200K トークン超で約54分放置した会話はアイドル圧縮。MCP の許可ルールは名指ししたサーバーだけに一致します●SONNET 4.5 — Claude API での提供終了は 11/30、残り45日。移行先は Sonnet 5.5●WINDOWS — 日本語の環境でだけフックが黙って壊れる報告があり、文字コードの確認が呼びかけられています●FAST MODE — Opus 5.5 の Fast mode がリサーチプレビューを終え、ベータヘッダーが不要になりました(10/15)●NEW — Cowork に渡したフォルダの先頭に、十行の約束ファイルを置いてみました●2.1.301 — vim の % モーション、VS Code パネルでの LaTeX 数式表示、使用量上限待ちのリトライ監視の上限が入りました(10/15)●2.1.299 — 200K トークン超で約54分放置した会話はアイドル圧縮。MCP の許可ルールは名指ししたサーバーだけに一致します●SONNET 4.5 — Claude API での提供終了は 11/30、残り45日。移行先は Sonnet 5.5●WINDOWS — 日本語の環境でだけフックが黙って壊れる報告があり、文字コードの確認が呼びかけられています●FAST MODE — Opus 5.5 の Fast mode がリサーチプレビューを終え、ベータヘッダーが不要になりました(10/15)●NEW — Cowork に渡したフォルダの先頭に、十行の約束ファイルを置いてみました
記事一覧/API & SDK
⬡ API & SDK/2026-03-27上級

Claude API プロダクション耐障害設計パターン — モデルルーティング・サーキットブレーカー・フォールバック戦略の実装ガイド

Claude APIを本番運用で支える耐障害設計の実装パターン。サーキットブレーカー、モデルルーティング、フォールバックチェーン、リトライ戦略、ディザスタリカバリをTypeScriptの実装コードと、運用で気づいた注意点を添えて整理しました。

api39production87resilience8circuit-breaker3retry6fallback8error-handling10typescript11

✦ プレミアム記事

深夜に走らせている定型処理のバッチが止まっていたことに気づいたのは、翌朝ログを開いたときでした。529 が返り、リトライが走り、そのリトライがまた 529 を呼び、ひと晩ぶんの処理が丸ごと落ちていました。手元のコードにはリトライもタイムアウトも書いてあったのです。書いてあったのに、足りませんでした。

レート制限、応答の遅れ、上流の一時停止——止まること自体は避けられません。避けられるのは、止まり方が雪崩に変わることだけです。

ここから先は、その雪崩を止めるために私が実際に入れている耐障害設計(Resilience Engineering)を、TypeScript の実装と、動かして測った数字で書き残します。

なぜLLMアプリケーションに耐障害設計が必要なのか

従来のWeb APIと比べて、LLMアプリケーションには特有の障害パターンがあります。

まず、応答時間の不確実性です。Claude APIの応答時間はプロンプトの複雑さやモデルの負荷状況によって数百ミリ秒から数十秒まで大きく変動します。固定タイムアウトでは対応しきれないケースが頻繁に発生します。

次に、レート制限のカスケード障害です。一つのリクエストがレート制限に達すると、後続のリクエストも連鎖的に失敗し、システム全体のスループットが急激に低下する「カスケード障害」が起きやすくなります。

さらに、コスト爆発リスクがあります。リトライ戦略を誤ると、障害時に無駄なAPIコールが急増し、コストが予想外に膨らむ危険性があります。

これらの課題に対して、本記事で紹介する5つのパターンを組み合わせることで、堅牢なプロダクションシステムを構築できます。なお、基本的なエラーハンドリングについてはClaude API エラーハンドリングとリトライ戦略で解説していますので、ここではその先のプロダクション設計に踏み込みます。

サーキットブレーカーパターンの実装

サーキットブレーカーは、連続的な障害を検出すると自動的にリクエストを遮断し、システム全体への障害伝播を防ぐパターンです。電気回路のブレーカーと同じ考え方で、Open(遮断)・Closed(通常)・Half-Open(試行)の3つの状態を持ちます。

// circuit-breaker.ts — Claude API用サーキットブレーカー実装
interface CircuitBreakerConfig {
  failureThreshold: number;    // Open状態に遷移する連続失敗回数
  resetTimeout: number;        // Open → Half-Open への待機時間(ms)
  halfOpenMaxAttempts: number;  // Half-Open 状態での最大試行回数
  monitorWindow: number;       // 失敗カウントのウィンドウ期間(ms)
}
 
type CircuitState = 'CLOSED' | 'OPEN' | 'HALF_OPEN';
 
class ClaudeCircuitBreaker {
  private state: CircuitState = 'CLOSED';
  private failureCount = 0;
  private lastFailureTime = 0;
  private halfOpenAttempts = 0;
  private successCount = 0;
 
  constructor(
    private config: CircuitBreakerConfig = {
      failureThreshold: 5,
      resetTimeout: 30_000,
      halfOpenMaxAttempts: 3,
      monitorWindow: 60_000,
    }
  ) {}
 
  async execute<T>(fn: () => Promise<T>): Promise<T> {
    // Open状態: リクエストを即座に拒否
    if (this.state === 'OPEN') {
      if (Date.now() - this.lastFailureTime >= this.config.resetTimeout) {
        this.transitionTo('HALF_OPEN');
      } else {
        throw new CircuitOpenError(
          `Circuit is OPEN. Retry after ${this.remainingResetTime()}ms`
        );
      }
    }
 
    // Half-Open状態: 試行回数を制限
    if (this.state === 'HALF_OPEN' &&
        this.halfOpenAttempts >= this.config.halfOpenMaxAttempts) {
      this.transitionTo('OPEN');
      throw new CircuitOpenError('Half-open attempts exhausted');
    }
 
    try {
      if (this.state === 'HALF_OPEN') this.halfOpenAttempts++;
      const result = await fn();
      this.onSuccess();
      return result;
    } catch (error) {
      this.onFailure();
      throw error;
    }
  }
 
  private onSuccess(): void {
    if (this.state === 'HALF_OPEN') {
      this.successCount++;
      // Half-Open で2回連続成功 → CLOSED に復帰
      if (this.successCount >= 2) {
        this.transitionTo('CLOSED');
      }
    }
    this.failureCount = 0;
  }
 
  private onFailure(): void {
    this.failureCount++;
    this.lastFailureTime = Date.now();
 
    if (this.state === 'HALF_OPEN') {
      // Half-Open での失敗は即座に OPEN へ
      this.transitionTo('OPEN');
    } else if (this.failureCount >= this.config.failureThreshold) {
      this.transitionTo('OPEN');
    }
  }
 
  private transitionTo(newState: CircuitState): void {
    console.log(`[CircuitBreaker] ${this.state} → ${newState}`);
    this.state = newState;
    if (newState === 'CLOSED') {
      this.failureCount = 0;
      this.successCount = 0;
    } else if (newState === 'HALF_OPEN') {
      this.halfOpenAttempts = 0;
      this.successCount = 0;
    }
  }
 
  private remainingResetTime(): number {
    return Math.max(
      0,
      this.config.resetTimeout - (Date.now() - this.lastFailureTime)
    );
  }
 
  getState(): CircuitState {
    return this.state;
  }
}
 
class CircuitOpenError extends Error {
  constructor(message: string) {
    super(message);
    this.name = 'CircuitOpenError';
  }
}
 
// 使用例
const breaker = new ClaudeCircuitBreaker({
  failureThreshold: 5,
  resetTimeout: 30_000,   // 30秒後に再試行
  halfOpenMaxAttempts: 3,
  monitorWindow: 60_000,
});
 
const result = await breaker.execute(async () => {
  // → Anthropic SDK の呼び出し
  return await anthropic.messages.create({
    model: 'claude-sonnet-4-6',
    max_tokens: 1024,
    messages: [{ role: 'user', content: 'Hello' }],
  });
});
// 期待出力: 正常時はAPIレスポンス、障害時はCircuitOpenError

ポイントは、monitorWindow を設定して一定期間内の失敗のみをカウントすることです。古い障害を永久に引きずってしまうと、一時的なネットワーク障害だけでブレーカーが頻繁に動作してしまいます。

✦

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

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
✦サーキットブレーカー閾値5/30秒・モデル別レイテンシSLO閾値などの具体パラメータと用途別のチューニング表
✦Cloudflare Workers の CPU 30秒制限下で ResilienceManager を分割する設計判断と Cron Triggers + Durable Objects への退避パターン
✦RTO/RPO を収益から逆算する表の作り方と、Supervisor を Sonnet → Haiku に切り替えてコストを抑える判断基準
Stripe による安全な決済 · いつでもキャンセル可能
✦

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

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

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

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

関連記事

⬡ API & SDK2026-04-23
Claude API の高可用性設計 — Sonnet / Haiku / Opus マルチモデルフォールバックを本番で成立させる
Claude API を単一モデル前提で組むと、障害やレート制限の瞬間にサービス全体が止まります。Sonnet・Haiku・Opus を段階的にフォールバックする本番実装を、コード・Circuit Breaker・ストリーミング対応まで含めて整理しました。
⬡ API & SDK2026-05-22
Claude の『このモデルは現在利用できません』が出る時に効くモデル選択フォールバックの設計
Claude API で『このモデルは現在利用できません(this model is currently unavailable)』と返ってきたとき、529 Overloaded やレート制限と同じ扱いにすると遠回りになります。エラーの種類を SDK の例外クラスで見分け、モデル ID をリクエスト単位で切り替えるフォールバックの実装と、思い込みで書きやすい落とし穴をまとめました。
⬡ API & SDK2026-05-22
Claude API の tool_result could not be submitted が再発しないための回復ハンドラ設計
Claude API でエージェントを長時間動かしていると、ある日突然 'tool_result could not be submitted' が連発し始めることがあります。再試行しても直らない、ストリーミング途中で死ぬ、そして次のセッションでもまた出る — 常時稼働のエージェント基盤で実際に踏み抜いた4種類の原因と、TypeScript で書いた回復ハンドラの実装を整理しました。