Amplify + Next.js 30秒以上のサーバ処理はタイムアウトとなる

2025/02/14に公開

要点

  • Amplify + Next.js(App Router)でフロントから呼び出すサーバ処理が30秒以上の場合、リクエストは504 Gateway Timeoutエラーとなる
    • ServerActionsとAPI Routesにおいて確認
  • 2025/02現在、30秒の上限を変更することはできない
  • 時間のかかる処理をAmplify外に移管し、ポーリング処理で状況を確認することで回避可能

該当Issue

タイムアウトの時間を引き上げる要望Issueが、AmplifyのGitHubリポジトリ上で作成されています。

https://github.com/aws-amplify/amplify-hosting/issues/3223

ポーリング処理による対応方法

サーバ処理が30秒を超えている場合、ポーリング処理に切り替えることでタイムアウトを回避可能です。

元の処理

次のサーバ処理(ServerActions)呼び出しは、実行に30秒以上かかるのでAmplify上ではタイムアウトするとします。
なお、下記の例では簡略化のためにエラー処理などを省略しています。

page.tsx
  const handleClick = async () => {
    await executeRequest();
  };
  // (中略...)
      <button onClick={handleClick}>Click</button>
action.ts
export async function executeRequest() {
  // 実行に30秒以上かかる
  const res = await fetch("https://...");
  const data = await res.json();
  return data;
}

ポーリング導入後の処理

Next.jsから呼び出すサーバ処理を、それぞれ30秒以内に完了する非同期リクエストAPIとポーリングAPIに変更します。時間のかかっていた部分は、Amplify外の非同期処理(Lambdaなど)に移管します。
ここでは移管したコードは省略し、Next.jsとしての実装の変更を記述します。

page.tsx
  const handleClick = async () => {
    await executeAsyncRequest();
    startPolling();
  };

  const startPolling = () => {
    // 10秒ごとにデータ状態を確認する
    const intervalId = setInterval(async () => {
      const data = await fetchPollingData();
      if (data.isSucceeded) {
        // 処理完了後、必要な操作(今回はダウンロード)を実行して定期実行を解除
        downloadData(data);
        clearInterval(intervalId);
      }
    }, 10000);
  };
  // (中略...)
      <button onClick={handleClick}>Click</button>
action.ts
export async function executeAsyncRequest() {
  // 非同期処理(Lambdaなど)を開始するAPIを呼び出す
  const res = await fetch("https://.../start-async");
  const data = await res.json();
  return data;
}

export async function fetchPollingData() {
  // データ状態(DBなど)を確認するAPIを呼び出す
  const response = await fetch("https://.../polling");
  const data = await response.json();
  return data;
}
NCDCエンジニアブログ

Discussion