できない.dev

Vercel の Serverless Function がタイムアウトする

Vercel Function は実行時間に上限がある。
Hobby は 10 秒、Pro は 60 秒(最大 300 秒まで `maxDuration` で延長)、Edge Runtime は 25 秒。
`maxDuration` 設定、`Promise.all` での並列化、ジョブキューへの退避、ストリーミングで切断回避の 4 系統で解決する。

#vercel#serverless#timeout#runtime#deploy

公開:

要約

Vercel Function のタイムアウト上限はプランと runtime で決まっている。
Hobby Serverless 10 秒 / Pro Serverless 60 秒(maxDuration で最大 300 秒)/ Edge 25 秒、が出発点。長すぎる処理は maxDuration で延ばすPromise.all で並列化するジョブキューに退避するストリーミングで切断を防ぐ、の 4 系統で解決する。

よくある原因

  1. Hobby の 10 秒上限: 何も指定しなければ Serverless Function は Hobby で 10 秒、Pro でも既定 15 秒で打ち切られる。
  2. maxDuration 未指定: Pro / Enterprise ではコード側で maxDuration を指定しないと既定値のままで、想定より早く切られる。
  3. 外部 API への直列呼び出し: 3 API × 4 秒の直列 fetch を書いていて、簡単に 10 秒を超える。
  4. Edge Runtime のストリーミング上限: Edge Runtime は 25 秒で接続を切られる仕様。
    長時間タスクには不向き。
  5. キュー退避をしていない: メール送信・PDF 生成・LLM 呼び出しなどの重い処理を 1 リクエスト内で完結させようとしている。

解決策

1. maxDuration を route で指定する

// app/api/heavy/route.ts (Pro plan)
export const maxDuration = 60;
 
export async function GET() {
  const data = await heavyJob();
  return Response.json(data);
}

公式の Configuring Functions / Duration のとおり、Pro 以上は最大 300 秒まで設定可能。
Hobby では maxDuration を書いても上限は 10 秒のまま。

2. 並列化して時間を縮める

const [a, b, c] = await Promise.all([fetchA(), fetchB(), fetchC()]);

3 つの直列 fetch(各 4 秒)が並列化で 4 秒前後に縮む。
fetch 同士に依存関係が無いケースでは最初に検討する。

3. Edge Runtime と Node Serverless の選び方

公式の Runtimes のとおり、軽量 API(認証、レスポンス整形、低レイテンシ)は Edge(コールドスタートほぼゼロ)、Node API 必須 / 長時間 / 重い処理は Node Serverless が原則。
Edge ではストリーミングで進捗を返し続ければ 25 秒上限内なら維持できる。

4. ジョブキューへ退避

長時間処理は Function 内で完結させず、QStash / Inngest / Upstash Queue 等の外部キューに enqueue だけして即 return する。
クライアントは別エンドポイントで進捗をポーリングする構成にする。

この記事は役立ちましたか?