RORK LABEN
NATIVE — Rork Max では AR / LiDAR スキャン、Metal を使った 3D、Dynamic Island、Siri Intents、HealthKit、NFC、App Clips、Core ML まで届きますIOS27 — iOS 27 Developer Beta 4 で Siri AI の対象が iPhone 15 Pro / 15 Pro Max・16 シリーズ・17 系へ広がり、応答が初期ベータより明確に速くなりましたDESIGN — iOS・iPadOS・macOS 27 向けの Apple 純正デザインキットが Figma と Sketch 向けに公開されました。新 OS の UI を組む段階で参照できますCANARY — Android 17(Cinnamon Bun)は従来の Developer Preview を廃し、継続更新される Canary ビルドへ移行しました。検証のタイミング設計が変わりますSPARK — Android 17 の Gemini Spark は、アプリを直接操作して配車の予約や注文といった複合的な作業を自動化しますSCALE — Rork は a16z から $2.8M を調達し、月間訪問は74万件規模まで伸びていますNATIVE — Rork Max では AR / LiDAR スキャン、Metal を使った 3D、Dynamic Island、Siri Intents、HealthKit、NFC、App Clips、Core ML まで届きますIOS27 — iOS 27 Developer Beta 4 で Siri AI の対象が iPhone 15 Pro / 15 Pro Max・16 シリーズ・17 系へ広がり、応答が初期ベータより明確に速くなりましたDESIGN — iOS・iPadOS・macOS 27 向けの Apple 純正デザインキットが Figma と Sketch 向けに公開されました。新 OS の UI を組む段階で参照できますCANARY — Android 17(Cinnamon Bun)は従来の Developer Preview を廃し、継続更新される Canary ビルドへ移行しました。検証のタイミング設計が変わりますSPARK — Android 17 の Gemini Spark は、アプリを直接操作して配車の予約や注文といった複合的な作業を自動化しますSCALE — Rork は a16z から $2.8M を調達し、月間訪問は74万件規模まで伸びています
記事一覧/開発ツール
開発ツール/2026-06-14上級

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

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

Rork525API通信Circuit Breaker指数バックオフタイムアウト2React Native218本番運用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-08-01
実験の割り当てが同じ端末に偏る — 100万件のIDで確かめたハッシュ選定と salt の位置
端末側で実験の変種を決める割り当てが、実験を2本並べた途端に同じ端末へ集中しました。100万件のIDで4つのハッシュを測り、原因がハッシュの一様性ではなく salt の連結位置にあったこと、そして採用した実装までを実測値とともに残します。
開発ツール2026-07-30
Renovate が触ってよい依存と、触ってはいけない依存 — Expo SDK 57 の123パッケージを機械的に切り分ける
Rork 生成アプリに依存の自動更新を入れると、Expo が版を管理している123パッケージまで巻き込まれます。2026年7月30日時点の実測では、うち6件が npm の最新版へメジャー更新される差でした。除外リストを手で書かず SDK から機械生成する手順をまとめます。
開発ツール2026-07-28
prebuild --clean で消える手入れを、上げる前に数える — Expo SDK 57 移行の棚卸し
Expo SDK 57 への移行前に、ios/ へ加えた手入れが prebuild の再生成でいくつ失われるかを数える手順をまとめました。素の差分649行のうち意味を持つのは3行。ノイズを正規化して実質的な変更だけを抽出するスクリプトと、config plugin への移し替えを実測つきで共有します。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →