ざっくりGCP料金計算

Cloud Runのタイムアウトを短くしすぎてPDF生成が全滅した話

深く考えずにデフォルト値を変更したら、重い処理が片っ端からタイムアウトした。

デプロイ翌日から「PDF生成ができない」報告が殺到した

デプロイの翌朝からサポートチームのSlackチャンネルに「PDF生成ボタンを押してもエラーになる」という報告が立て続けに届いた。Cloud Runのログを見ると「deadline exceeded」エラーがPDF生成のエンドポイントから大量に出力されていた。他のAPIは正常に動いている。PDF生成だけが軒並み失敗していた。

前日のデプロイ内容を確認すると、Cloud Runのリクエストタイムアウト設定を変更していた。デフォルトの300秒を使っていたが、「通常のAPIは1秒以内に返るのに300秒は長すぎる。60秒に短くしよう」という判断で変更していた。この変更がPDF生成処理を全滅させた原因だった。

なぜPDF生成だけ影響を受けたか

このサービスのPDF生成処理は内容によって処理時間が大きく変わる。シンプルなテキストのみのドキュメントなら5秒程度で終わるが、図表が多いレポートや数十ページに渡る契約書のPDFを生成する場合、3〜5分かかることがある。ユーザーによって生成するPDFの内容が全く異なり、重いPDFを生成しようとしたユーザーが全員60秒のタイムアウトに引っかかって失敗した。「ほとんどのAPIは1秒以内」という判断は正しかったが、「すべてのAPIが1秒以内」ではなかった。1つのCloud RunサービスにAPIエンドポイントとPDF生成エンドポイントが同居していたため、60秒のタイムアウト設定がPDF生成にも適用された。タイムアウトの変更前に全エンドポイントの処理時間分布をCloud Monitoringで確認していれば、p99レイテンシでPDF生成の処理時間が長いことに気づけた。

非同期化による根本解決

即座の対応としてタイムアウトを元の300秒に戻した。根本的な解決として、PDF生成処理をCloud Run Jobsに切り出してバックグラウンド実行に変更した。ユーザーがPDF生成をリクエストするとジョブIDが返り、ポーリングでジョブの完了を確認してからダウンロードリンクを提供する非同期フローに変えた。これによりHTTPリクエストのタイムアウト制限を受けずに処理でき、ユーザーも「生成中です」というUXで待てるようになった。設定変更の影響範囲を事前に把握することの重要さと、重い処理は非同期設計にすべきだという教訓を同時に学んだ出来事だった。