このブログのサイドバーにある機能が、本番環境で動いていないことに気がついた。ローカルでは正常に動いているのに、本番だけ表示されない。
コンソールを開いてみると、ある API エンドポイントが 404 を返していた。Cloudflare Pages に Pages Functions としてデプロイしているはずなのに、なぜルートが見つからないのか。設定ミスを疑い始めたところで、メールを確認した。
原因はメールボックスにあった
Cloudflare からこんなメールが届いていた。
お使いのアカウントは、Cloudflare Workers または Pages Functions の 1 日あたりのリクエスト制限を超えました 1 日あたりのリクエスト制限: 100,000
無料枠の 10 万リクエスト/日を超えたため、Worker が落ちていたのだ。設定ミスではなく、単純にリクエスト数の問題だった。
Workers の無料枠は「無料だからゼロリスク」ではなく、超えたら Worker が停止する仕組みになっている。静的サイトのちょっとした Pages Functions だから大丈夫だろうと油断していたが、bot やクローラーのリクエストも全部カウントされるため、個人ブログでも意外と早く上限に達する。
同じアカウントで動かしている別サービスへの影響
このブログの機能が動かなくなるのも困るが、より深刻なのは同じ Cloudflare アカウントで運用している別のサービスだった。
そのサービスはブログと違い、リクエストのたびに毎回 Worker が発火する構成になっている。操作のたびにさらに Worker が呼ばれるため、1 セッションあたりのリクエスト消費量がかなり多い。
そして重要なのが、Cloudflare の 10 万リクエスト/日はアカウント全体の合算という点だ。複数のサービスが 1 つの無料枠を取り合っている。制限を超えると、Worker に依存しているサービスはページ自体が丸ごと表示されなくなる。
Workers Paid に移行する
選択肢は単純だった。
- 無料枠内に収まるよう最適化する(bot を弾く処理など)
- $5/月の Workers Paid プランに移行する
別サービスのデータは D1 に大量に入っており、Worker なしで動かす設計に変えるのはかなりの改修が必要だ。$5/月 でアカウント内の全 Worker が月 1,000 万リクエストまで使えるようになるなら、コスト対効果で素直に払う方が合理的だと判断した。
「一億円請求されたら終わる」問題
有料プランに移行すると従量課金が始まる。当然湧いてくる不安が「どこまで膨らむかわからない」というものだ。
実際の料金は超過分 $0.30 / 100 万リクエストなので、個人サービスの規模で天文学的な金額になることはまずない。1 日 100 万リクエストが来ても月 $9 程度の追加料金だ。ただ、「まずない」と「絶対ない」は違う。支出の上限を自分で把握したいという気持ちは当然ある。
Cloudflare のダッシュボードには通知設定があり、「$XX を超えたらメールを送る」という閾値を設定できる。ただしハードな停止機能はない。あくまで通知だけだ。
Terraform で支出アラートを設定する
インフラは既に Terraform で管理しているので、アラートも Terraform から設定することにした。cloudflare_notification_policy リソースを使う。
$10 刻みで $10〜$100 の 10 段階でアラートを設定した。
resource "cloudflare_notification_policy" "workers_spending_alert" {
count = 10
account_id = local.account_id
name = "Workers 支出アラート $${(count.index + 1) * 10}"
alert_type = "billing_usage_alert"
enabled = true
email_integration {
id = "[email protected]"
}
filters {
limit = [tostring((count.index + 1) * 10)]
}
}
一点ハマったのが filters の product フィールドだ。最初 product = ["workers"] と書いたところ、Error 17106: Invalid product selection で弾かれた。product フィルターを外してアカウント全体の支出アラートにしたところ正常に動いた。
「無料だから」と放置していたインフラ周りが、実際に問題が起きてから一気に整備されていく。今回は金額的なダメージはなかったが、別サービスが丸ごと落ちていたかもしれなかったことを考えると、早めに気づけて良かった。