Cloudflare Workers 無料プランで 503 が出る原因は CPU 上限
Cloudflare Workers で運用しているサイトが、断続的に 503 を返していました。しかもアクセスが集中していたわけではありません。毎分 10〜31 リクエスト、つまり秒間 0.5 程度の負荷で、4 回に 1 回が失敗していました。
同じサイトが別の時間帯には 1 時間あたり 2,516 リクエストをエラーゼロで捌いています。負荷では説明が付かない。
原因は無料プランの CPU 時間の上限でした。ただしこの上限は「1 リクエストあたり 10 ミリ秒」という単純な形では効いてきません。そこを理解していないと、いつまでも原因にたどり着けません。
症状
Cloudflare のログを集計すると、こうなっていました。
2026-08-05T04:40:00Z req= 14 5xx=10 失敗率=71%
2026-08-05T04:44:00Z req= 31 5xx= 1 失敗率= 3%
2026-08-05T05:01:00Z req= 14 5xx= 8 失敗率=57%
合計 req=1035 / 5xx=239 (23.1%) 最大 31 req/分約 45 分間続き、失敗率は 13〜71% の間で揺れました。リクエスト数と失敗率が相関していません。 31 req/分のときに 3%、14 req/分のときに 71% です。
失敗していたのは実在する記事ページで、手動でアクセスすると 200 が返ります。恒常的な障害ではなく、断続的に混ざる。
効かなかった切り分け
先に、潰しても答えにたどり着かなかった仮説を挙げておきます。
- デプロイ直後の不安定 — その日はデプロイしていませんでした
- Cloudflare 側の障害 — 同じ時間帯、同じアカウントの他 7 サイトは 5xx がゼロでした
- データベースの暴走 — クエリ数は増えていましたが、リクエスト数に比例した増え方で、1 リクエストあたりの本数は平常時と同じでした
- 特定ページの不具合 — 失敗は多数のパスに 2 件ずつ薄く分散していました
- 単純な過負荷 — 前述のとおり、同じサイトがその 3 倍の負荷をエラーゼロで処理しています
ここまで潰すと、残るのは「リクエストごとに与えられた何かの資源を使い切っている」という筋だけになります。
原因は CPU 時間だった
Workers のログを取得して、outcome を集計したら一発でした。
exceededCpu: 274 件 ← 56%
ok: 216 件
canceled: 1 件
CPU 時間(ms) p50=10 p90=115 p99=221 max=291exceededCpu は Cloudflare が「CPU の上限を超えた」と明示的に記録するものです。推測ではありません。
無料プランの上限は公式ドキュメントにあるとおり 1 リクエストあたり CPU 10 ミリ秒です。有料プランは既定 30 秒なので、桁が 3 つ違います。
そして Cloudflare のエラー 1102(Worker がリソース上限を超過)は、HTTP 503 として返ります。 例外による 1101 は 500 です。観測された内訳は 503 が 302 件・500 が 2 件で、「大半がリソース上限、まれに例外」という分布と一致していました。
なぜ低負荷でも落ちるのか
ここが理解の要です。上限は 10ms ですが、Cloudflare は一時的な超過を許容し、平均で帳尻を合わせています。
上の実測値を見ると、p90 で 115ms、最大で 291ms 使ったリクエストが成功しています。10ms の 29 倍です。単発なら通る。
しかし連続して重いページを処理すると、この余力が枯渇します。 枯渇したあとは 10ms で強制終了され、503 になる。
つまり瞬間の負荷ではなく、蓄積した予算の問題です。だから次のような、一見矛盾した挙動になります。
- 毎分 14 リクエストでも失敗する(余力が尽きているとき)
- 1 時間 2,516 リクエストでも無事(余力が回復しながら処理できているとき)
引き金はクローラーでした。サイトを一巡するために、重いページを連続で要求してきます。人間の閲覧と違って間隔が空きません。
何が CPU を食っていたか
パスの種類ごとに分けると、こうなりました。
- 記事ページ: 426 件中 234 件が失敗(55%)、CPU 最大 291ms
- カテゴリページ: 49 件中 40 件が失敗(82%)、最大 73ms
- 記事一覧: 10 件中 0 件が失敗、最大 59ms
- トップ: 5 件中 0 件が失敗、最大 76ms
失敗率だけ見るとカテゴリページが目立ちますが、件数でも失敗数でも CPU 最大値でも記事ページが支配的です。本文のレンダリングが主犯でした。Astro 製の CMS「EmDash」 の Portable Text(構造化データ)を HTML に変換する処理で、記事が長いほど重くなります。
これは 1 サイトの問題ではありませんでした
同じ構成の全 8 サイトについて、直近 24 時間の CPU 時間を測りました。
- サイト A: 486 リクエスト中 220 件が 10ms 超、p50 7ms、最大 130ms
- サイト B: 519 リクエスト中 186 件が 10ms 超、p50 13ms、最大 269ms
- サイト C: 636 リクエスト中 316 件が 10ms 超、p50 21ms、最大 447ms、`exceededCpu` が 5 件発生済み
- サイト D(今回落ちたサイト): 284 リクエスト中 189 件が 10ms 超、p50 16ms、p90 199ms
全サイトでリクエストの 2〜9 割が 10ms を超えていました。 落ちたサイトが特別だったのではなく、たまたま最初に大きなクロールを受けただけです。サイト C では既に失敗が始まっていました。
測り方
同じ状況を疑うなら、Workers のログを見るのが最短です。ダッシュボードの Workers & Pages から対象の Worker を開き、Logs を見ます。outcome が exceededCpu になっていれば確定です。
API から集計する場合は、observability のクエリ API に $workers.outcome と $workers.cpuTimeMs があります。トークンには Workers Observability の読み取り権限が必要です。
なお無料プランのログ保持は 3 日間です。障害から日が経つと消えるので、気付いたら早めに見てください。
一方で、Cloudflare のアクセス解析(GraphQL Analytics)だけを見ていても原因にはたどり着けません。 そこで分かるのはステータスコードとパスまでで、exceededCpu は出てきません。私は最初これだけを見て、負荷やデプロイや障害を疑って時間を溶かしました。
対処
上限そのものは無料プランでは動かせないので、方向は 2 つです。
1. Worker の実行回数を減らす
エッジキャッシュを効かせて、一度描画したページを次から Cloudflare に返させます。CPU 予算の消費そのものを止めるので、これが本命です。ただし Cloudflare は HTML を既定ではキャッシュしないため、明示的な設定が要ります。この話はCloudflare は HTML をキャッシュしないに分けて書きました。
2. レンダリングを軽くする
p90 で 115〜199ms 出ているものを 10ms に収めるのは非現実的です。1 の補助にはなりますが、単独では届きません。
3. 有料プランにする
CPU 上限が 10ms から 30 秒になるので、この種の問題は構造的に消えます。月 5 ドルです。ただし「毎リクエストで全部描き直している」という非効率は残るので、キャッシュは別途やる価値があります。
私は 1 を選びました。無料プランのまま、実行回数を減らす方向です。
追記: キャッシュを入れても書き込みは守られない
エッジキャッシュを 8 サイトに入れたあと、記事本文を一括で書き換える作業をしました。57 記事に対して更新と公開を連続で流したところ、CPU 上限超過が 115 件出ました。
直近 3 時間: Worker 実行 1,793 件 / CPU 上限超過 115 件(すべて失敗)
CPU 時間の中央値: 10ms ちょうど(上限で頭打ち)キャッシュが効くのは読み取り側だけです。管理画面と API は毎回サーバーまで届くので、上限に当たる条件は導入前と変わりません。実際、更新が 2 回、公開が 6 回、途中で 503 になりました(いずれも再実行で成功しています)。
なぜ一括処理だと当たるのかというと、CPU の予算が時間あたりの平均で回復する仕組みだからです。1 本ずつ手で編集している限り予算は回復しますが、数十本を続けて流すと回復が追いつきません。
被害がどこで止まるかも書いておきます。落ちるのは書き込み処理そのものなので、公開中のページには影響しません。失敗したリクエストをやり直せば通ります。ただし、
- 一括処理はリトライ前提で組む。1 回の失敗で全体を止めない
- 何件成功したかを必ず数える。成功前提で進めると、途中まで書き換わった状態に気づけない
読み取り側については、同じ期間に公開ページ側の CPU 上限超過は 8 サイトすべてで 0 件でした。キャッシュは効いています。効く範囲が読み取りに限られる、というだけの話です。
無料プランで運用するなら
今回のことで、無料プランの CPU 上限は「めったに当たらない上限」ではなく、普通の CMS サイトが日常的に触る上限だと分かりました。記事本文のレンダリングだけで 100ms 台に乗ります。
そのうえで落ちていないサイトが多いのは、エッジキャッシュが効いていないのに、クローラーが連続で来ていないからという、かなり運任せの状態でした。
同じ構成で運用しているなら、落ちる前に一度 CPU 時間を測っておくことをお勧めします。p50 が 10ms を超えていたら、いつ落ちてもおかしくありません。
無料プランの他の上限についてはCloudflare Workers 無料プランの 3 MB 上限に、商用利用の可否についてはCloudflare Pages の無料プランは商用利用できるに書いています。