Firebase Hosting + Cloud Functions で 502 Bad Gateway が出たときの切り分けと対処法
長時間のスキャン処理で 502 に悩んだときの構造的理解と手順を、未来の自分向けに整理したメモです。
現象:timeoutSeconds を延ばしても 502 が消えない
Hosting の rewrites で /api/** を Cloud Functions(2nd gen/Cloud Run 上)に流している構成で、実行時間の長い処理(例:外部 API を繰り返し叩くスキャン)を同期 HTTP で呼び出すと、ブラウザでは 502 Bad Gateway が返ることがあります。
Cloud Functions 側の timeoutSeconds を大きくしても改善しない場合、原因は「バックエンドが落ちている」だけではなく、リクエストの経路(どのレイヤーが先に諦めるか)にあります。
原因:前段(Hosting 層)と後段(Functions)のタイムアウトは別物
Hosting 経由で Functions に届ける経路では、クライアントが応答を待てる時間に、プラットフォーム側の上限が別レイヤーでかかる、と理解すると切り分けしやすいです。実務上・コミュニティ上は、おおよそ 60 秒前後で接続が切れ、クライアントからは 502 に見える、という観測がよく共有されます(数値や挙動は更新で変わりうるため、詰まったときは当該時点の公式情報も確認してください)。
イメージとしては、後段の Functions はまだ処理を続けていても、前段の門番が先に接続を閉じるため、ブラウザだけが 502 を見る、という状態です。timeoutSeconds を伸ばしても、この前段の壁は増えない、と覚えておくと混乱が減ります。
教訓: 502 のときは「バックエンドのバグ」一択と決めつけず、Hosting リライト経由か、Functions(Cloud Run)の直 URL かを切り分ける。
回避策:Hosting をバイパスして直 URL を叩く
設定ファイルを後から見返すときの対応関係は次のとおりです。
firebase.json…/apiを Functions に回す Hosting 経由の道(長時間処理には弱いことがある)。.env(および Vite のimport.meta.env)… ビルド時に Cloud Run のオリジンを埋め込み、fetchを Hosting を迂回する道に切り替える。
手順の例です。
- URL の確認:
firebase deploy完了時のログに出るFunction URLを控える(例:https://api-xxxxxx-xx.a.run.app)。 - 環境変数: フロントのビルド時変数(例:
VITE_API_ORIGIN)に、https://からホストまで(末尾スラッシュなし)を設定する。 - API クライアント:
/api相対ではなく${VITE_API_ORIGIN}/api/...のように、直オリジンに向ける。 - CORS: 別オリジンから叩くため、Functions 側で
cors: true等、ブラウザからの呼び出しに必要な設定をしておく。 - 再ビルド・再デプロイ: Vite は
VITE_*をビルド時に埋め込むため、.env変更後はビルドからやり直す。
App Check を入れる場合のメモ
個人ツールでは App Check を入れず、直 URL + Firebase Auth の ID トークンで済ませたケースです。将来 App Check で締める場合、検証フローが Hosting 前提になりやすく、直 URL だけでは運用が重くなる可能性があります。そのときは、後述の非同期ジョブ化へ寄せて、長い処理を同期 HTTP に載せない設計が現実的です。
中長期的な改善:非同期ジョブ化
直 URL でも、処理時間やクライアント側の制約は残ります。理想的には、リクエストを受け取ったらすぐジョブ ID(例:scanId)を返し、処理はバックグラウンドで実行し、フロントは Firestore 等をポーリングして進捗を確認する、という形に移行すると、ゲートウェイの種類に依存しにくくなります。
運用メモ:デプロイログはどこに出るか
Firebase Console の Hosting「リリース履歴」は、いつデプロイしたかの記録であり、CLI の詳細ログの代替にはなりません。firebase deploy を実行したターミナルに、Function URL を含む出力が出ます。ファイルに残す例:
npm run build && firebase deploy 2>&1 | tee firebase-deploy.log
まとめ
- 長時間の同期 HTTP は、Hosting 経由だと 502 が出やすい(前段の時間制限)。
- Functions(Cloud Run)の直 URLをフロントに埋め込む手が、手軽な回避策になりうる。
- 非同期ジョブ化が、中長期では最も堅牢な方向。
- 半年後に
firebase.jsonと.envを見たとき、どちらの経路を指しているか辿れるよう、メモや記事を残しておく。