RORK LABEN
ENGINE — Rork MaxはClaude CodeとClaude Opus 4.6を基盤に、ネイティブSwiftアプリを直接生成しますCORE ML — Rork MaxからCore MLの端末内推論・HealthKit・HomeKit・NFC・App Clipsといった機能に手が届きますSEED — Rorkは2026年4月にLeft Lane Capital主導で$15Mのシードを調達し、Peak XVやa16z Speedrunが参加しましたM&A — Rorkはアプリビルダー Paperline を買収し、エンジニアリング人材の獲得を目的に買収を継続する方針ですMARKET — Gartnerは2026年末までに新規アプリの75%がローコードまたはノーコードで作られると予測していますGROWTH — ノーコードAI市場は2024年の$4.9Bから2029年に$24.8Bへ、年38.2%の成長が見込まれていますENGINE — Rork MaxはClaude CodeとClaude Opus 4.6を基盤に、ネイティブSwiftアプリを直接生成しますCORE ML — Rork MaxからCore MLの端末内推論・HealthKit・HomeKit・NFC・App Clipsといった機能に手が届きますSEED — Rorkは2026年4月にLeft Lane Capital主導で$15Mのシードを調達し、Peak XVやa16z Speedrunが参加しましたM&A — Rorkはアプリビルダー Paperline を買収し、エンジニアリング人材の獲得を目的に買収を継続する方針ですMARKET — Gartnerは2026年末までに新規アプリの75%がローコードまたはノーコードで作られると予測していますGROWTH — ノーコードAI市場は2024年の$4.9Bから2029年に$24.8Bへ、年38.2%の成長が見込まれています
記事一覧/開発ツール
開発ツール/2026-06-14上級

Rork アプリの API 通信を障害に強くする — Circuit Breaker・指数バックオフ・タイムアウトを実装で固める

Rork で生成したアプリの API 通信を本番品質に引き上げる実装メモ。タイムアウト・指数バックオフ・Circuit Breaker を段階的に組み込み、依存 API が不安定でも自動回復する通信層を設計します。

Rork498API通信Circuit Breaker指数バックオフタイムアウト2React Native201本番運用10

プレミアム記事

リリース直後のアプリで、API のエラー率が一晩で 5% を超えたことがあります。

依存していた外部 API が応答を遅延させ始め、タイムアウトを持たない fetch がそのまま詰まっていく。画面にはスピナーが回り続け、ユーザーには何が起きているのか伝わらない。ログを追って原因にたどり着いた頃には、すでに数百件のエラーレポートが積み上がっていました。あのとき通信層に最低限の防御があれば、被害は十分の一で済んだはずです。

個人開発でアプリを回していると、こうした通信の防御は後回しになりがちです。Rork でアプリを組むと、生成される API 呼び出しは素直な fetch です。開発中はそれで困りません。問題は、本番のネットワークが開発環境とはまるで別物だという点にあります。地下鉄で電波が切れ、Wi-Fi と 5G を行き来し、依存サービスが数分だけ不調になる——こうした揺らぎを前提にした通信層を、後付けではなく設計として持っておきたいところです。

ここでは Rork アプリの通信を本番品質へ引き上げる過程を、実際に動くコードとともに実装メモとして残します。派手な仕組みではありません。タイムアウト、指数バックオフ付きのリトライ、Circuit Breaker。この三つを正しい順序で重ねるだけで、依存 API が傾いてもアプリが巻き添えにならない通信層になります。

素の fetch が本番で崩れる三つの瞬間

最初に、何から守るのかをはっきりさせておきます。Rork が吐く典型的な呼び出しはこの形です。

const fetchUser = async (userId: string) => {
  const res = await fetch(`https://api.example.com/users/${userId}`);
  if (!res.ok) throw new Error("Failed to fetch user");
  return res.json();
};

このコードが本番で崩れる瞬間は、経験上ほぼ三つに集約されます。

一つ目は一時的な切断です。モバイル回線は一瞬で復活することが多く、本来なら一度リトライすれば通る通信を、そのままエラーとしてユーザーに見せてしまいます。二つ目は無限待機です。fetch にはタイムアウトがないため、応答しないサーバーを待ち続け、スピナーが何十秒も回ります。三つ目が連鎖障害です。遅い API を待つリクエストが積み上がり、すでに壊れている相手へ送り続けることで、自分側の状態まで悪化させます。

この三つに、それぞれタイムアウト・リトライ・Circuit Breaker が対応します。導入する順序もこの通りが現実的です。効果が出るのが早く、実装コストが低いものから入れていきます。

まずタイムアウト — 今日入れて一番効く一手

無限待機を断つだけで、ユーザー体感のエラーの大半は消えます。2026 年時点では AbortSignal.timeout() が React Native でも使えるようになり、AbortController を手で組む必要が薄れました。ただし「どのエラーがタイムアウト由来か」を呼び出し側で判別できるよう、独自のエラー型に正規化しておきます。

export class ApiError extends Error {
  constructor(
    message: string,
    public readonly statusCode: number,
    public readonly body?: unknown,
  ) {
    super(message);
    this.name = "ApiError";
  }
}
 
interface TimedFetchOptions extends RequestInit {
  timeoutMs: number;
}
 
export async function fetchWithTimeout(
  url: string,
  { timeoutMs, signal, ...init }: TimedFetchOptions,
): Promise<Response> {
  // 呼び出し側の signal(アンマウント等)と timeout を合成する
  const timeoutSignal = AbortSignal.timeout(timeoutMs);
  const merged = signal
    ? AbortSignal.any([signal, timeoutSignal])
    : timeoutSignal;
 
  try {
    const res = await fetch(url, { ...init, signal: merged });
    if (!res.ok) {
      const body = await res.json().catch(() => null);
      throw new ApiError(`HTTP ${res.status} ${res.statusText}`, res.status, body);
    }
    return res;
  } catch (err) {
    // timeout 由来の中断を 408 に正規化し、呼び出し側で扱いやすくする
    if (err instanceof DOMException && err.name === "TimeoutError") {
      throw new ApiError(`Request timed out after ${timeoutMs}ms`, 408);
    }
    throw err;
  }
}

タイムアウト値は一律にしないほうが扱いやすいです。私は用途で三段階に分けています。一覧取得のような軽い GET は 5〜8 秒、ユーザー操作に紐づく詳細取得は 8〜12 秒、アップロードや重い処理は 30〜60 秒。短すぎると低速回線のユーザーに不要なエラーを見せ、長すぎると無限待機の問題が戻ってきます。AbortSignal.any() で画面側の中断シグナルと合成しておくと、コンポーネントがアンマウントされた瞬間に通信も確実に止まります。

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

この記事の続きを読む

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

この記事で得られること
タイムアウト→リトライ→Circuit Breaker を段階導入する実装順序と、それぞれの具体的なしきい値の決め方
AbortSignal.timeout() と指数バックオフ+ジッターを組み合わせた、コピーして動く通信クライアントの全コード
Circuit Breaker の状態をスナップショットで観測し、TanStack Query と二重リトライさせない統合パターン
Stripe による安全な決済 · いつでもキャンセル可能

この記事を購入する

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

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

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

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

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

関連記事

開発ツール2026-07-10
React Compiler を Expo に入れて、手書き memo を 41 箇所消しました
Rork が生成した React Native 画面に React Compiler を導入し、再レンダリング回数を Profiler で実測しました。手書き memo/useCallback の削除判断、効かない箇所の見分け方、CI での回帰検知までをまとめています。
開発ツール2026-07-07
アイコンのバッジが「3」のまま消えない — Expoアプリのバッジ数をSource of Truthで作り直す
Expoアプリのアイコンバッジが実際の未読と食い違い、消えなくなる原因を突き止め、バッジ数を状態から再計算して同期するSource of Truth設計を、動くコードと実運用の落とし穴つきで整理します。
開発ツール2026-07-04
「続きを読む」を出すべきか、テキストの実測で決める — Rork(Expo)の折りたたみ表示設計
商品説明やレビュー本文を3行で畳み「続きを読む」を出す実装で、短い文にまでトグルが付いてしまう問題を解決します。onTextLayout で実際の行数を測り、はみ出す時だけトグルを出す設計を、iOS と Android の差、展開アニメーション、文字サイズ拡大への配慮まで動くコードでまとめます。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →