この記事は、Cloudflare上でAIプロダクトを運用する中で見つけた落とし穴シリーズの1本である。自社が受託する地域観光案内サービスで、日次の利用予算を管理するDurable Objectを実装したところ、アクセスが増えた日にAI機能全体が止まった。原因はリクエスト数の上限ではなく、別枠のSQLite書き込み行数だった。
この記事で分かること
- Durable Objects SQLiteの無料枠がリクエスト数とは別枠であること
- 書き込みが二乗で増える設計の何が問題か
- 原因を1回で特定した診断方法
この記事で分からないこと(正直に書く)
- 本記事の元になった実装以外に、同種の全件削除・全件書き直しの設計が社内の他のWorkerに残っていないかは、本記事の材料だけでは分からない
何が起きたか
日次の利用予算を管理するDurable Object(日付ごとに1オブジェクト)を公開した後、アクセスが増えた日の特定の時間帯に呼び出し件数がおよそ470件に達し、その1時間だけで449,165行の書き込みが発生した(出所: 自社の運用記録、確認日2026-09-06)。Cloudflareの公式ドキュメントでも、Workers Freeプランの場合、SQLiteを使うDurable Objectsの1日あたりの書き込み行数は10万行まで、読み取りは1日500万行までと明記されている(https://developers.cloudflare.com/durable-objects/platform/pricing/, 確認日2026-09-06)。1時間で上限の4倍以上を消費し、超過後はアカウント内の他のSQLite系Durable Objectsも含めて書き込みが失敗し、AI機能を担う別のオブジェクトも巻き添えで動かなくなった。
なぜ気づけなかったか
呼び出しのたびに、その日の予約状態を全件読み込んでからテーブルを丸ごと削除し、全件を書き直す実装になっていた。メモリ上で状態を持つ実装をSQLiteにそのまま移植したことが原因で、呼び出し回数が増えるほど1回あたりの書き込み行数も増える二乗の関係になっていた。Workersのリクエスト数自体は上限の5%程度しか消費しておらず(出所: 自社の運用記録、確認日2026-09-06)、この数字だけの監視では異常に気づけない。書き込み行数は別枠で計測されており、それを見て初めて実態が分かった。
どう直したか
GraphQL Analyticsで、Durable Objectごとの書き込み行数を分解して見たところ、原因のオブジェクトに一撃で絞り込めた。実装は、全件の削除・再書き込みをやめ、予約時は1行の追加と1行の更新、確定時は該当する1行だけの更新とテーブルへの反映に変える差分更新に直した。あわせて、予算チェックの失敗がAI機能本体を巻き込まないよう、判定に失敗した場合は制限しない方向に倒す設計にした。応急処置としては、Workers Paidプランに切り替えることで、超過分が停止ではなく従量課金になる点も確認している。
同じ構成の製品で先に見る場所
自社はカンタン補助金や弁護士みつかるなど複数のプロダクトでDurable Objectsを使っている。同じ構成のプロダクトでは、まずDurable Objects内の状態更新が「全件読み込み→全件削除→全件書き直し」になっていないかを確認するのが最初の一手になる。呼び出し1回あたりの書き込み行数がテーブルサイズに比例する実装は、アクセスが増えるほど無料枠に近づく。監視は、Workersのリクエスト数だけでなく、Durable Objects側の書き込み行数を別に見る必要がある。
無料枠がリクエスト数とは別枠になっているという見落としは、静的アセットがWorkerを素通りする記事やX-Real-IPの記事とも通じる。関連してRAGの保管費用の記事も参照してほしい。
自社のDurable Objects設計・コスト管理について相談したい場合は、お問い合わせから編集部まで連絡してほしい。
よくある質問
Q1. Durable ObjectsのSQLite無料枠が超過するとどうなるか
超過したDurable Objectだけでなく、同じアカウント内の他のSQLite系Durable Objectsも巻き添えで書き込みが失敗する状態になる。
Q2. なぜWorkersのリクエスト数を見ていただけでは気づけなかったのか
リクエスト数は上限の5%程度しか消費しておらず異常に見えなかった。SQLiteの書き込み行数はリクエスト数とは別枠で計測されている。
Q3. 原因はどうやって1回で特定できたのか
GraphQL AnalyticsでDurable Objectごとの書き込み行数を分解して見たところ、原因のオブジェクトに一撃で絞り込めた。