Netlify Scheduled Functionsが動かない・ログも空|原因はNext.jsのmiddlewareでした

記事のアイキャッチ。「予約実行が動かない エラーも出ない」の文字と、歯車の機械の前で首をかしげるロボット AI・開発の記録

症状

Netlifyのスケジュール実行(Scheduled Functions)を設定したのに、3日間、一度も実行されませんでした。

このとき、こういう状態でした。

  • デプロイは成功していて、関数も「スケジュール済み」として認識されている
  • 関数が呼ぶエンドポイントは、手で叩くと正常に応答する
  • Netlifyの関数ログが空。デプロイしてから1回も呼ばれた記録がない
  • エラーが1つも出ていない

失敗したのではなく、処理そのものが始まっていませんでした。

環境

  • Next.js(App Router)
  • proxy.ts(Next.jsのmiddlewareにあたるもの。バージョンによっては middleware.ts
  • Netlify(Scheduled Functions)
  • 認証あり(未ログインならログイン画面へ飛ばす作り)

原因

middlewareが、Netlifyの関数へのリクエストをログイン画面へリダイレクトしていました。

予約実行の流れ。時間になっても門番に止められ、ログイン画面へ送られてしまい、仕事場には一度もたどり着いていない様子

Netlifyのスケジュール関数は、/.netlify/functions/... というパスを呼びに来ます。

このパスがmiddlewareの対象に入ったままだったので、こうなっていました。

  1. Netlifyが時刻どおりに /.netlify/functions/... を呼ぶ
  2. middlewareがセッションを確認する
  3. ログイン中のユーザーがいないので、ログイン画面へリダイレクトする
  4. 関数の中身が実行されない
  5. 何も実行されていないので、関数ログにも何も残らない

エラーが出なかったのは、仕事が始まる前に追い返されていたからでした。

直し方

matcher と、middlewareの本体の両方で /.netlify を通します。片方だけでは足りません。

// proxy.ts(middleware.ts)
export async function proxy(request: NextRequest) {
  // /.netlify 配下はNetlify自身の入口(予約実行される関数など)
  if (request.nextUrl.pathname.startsWith('/.netlify/')) {
    return NextResponse.next({ request })
  }

  // ...以下、通常の認証処理
}

export const config = {
  matcher: [
    '/((?!_next/static|_next/image|favicon.ico|\\.netlify|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)',
  ],
}

「認証を外して大丈夫?」について

関数側が自前の合言葉(環境変数)で守られていることが前提です。

私の場合は CRON_SECRET という環境変数を関数側で検証していて、値が合わなければ処理しません。未設定なら実行口そのものが止まる作りにしてあります。だから、middlewareを通しても新しく開いた穴はありません。

修正後、次を確認しました。

  • 認証で守っている管理画面は、変わらず401
  • 公開ページは、変わらず200
  • 予約実行が、指定した時刻ちょうどに動いた

なぜ3日も気づかなかったか

作ったときに動作確認はしていました。そして、その確認は間違っていませんでした。

ただ、確認した入口と、本番で使われる入口が違っていました。

/api は、もともとmiddlewareの対象から外してありました。手で動作確認したのも /api でした。だから通りました。

でも、Netlifyのスケジュール実行が実際に使うのは /.netlify/functions/... のほうでした。そちらは一度も試していませんでした。似ているので、同じように動くと思っていました。

「動作確認しました」は嘘ではなく、「何を確認したのか」を確認していませんでした。

同じ状態か確かめる手順

  1. Netlifyの管理画面で、対象の関数のログが空かどうかを見る(空=呼ばれていない。エラーが出ている=別の原因)
  2. 関数のURLをブラウザで開いてみる。ログイン画面にリダイレクトされたら、これ
  3. middlewareの matcher\.netlify の除外が入っているか確認する

一番の学び

失敗はうるさいので気づけます。赤い文字が出るし、記録も残ります。

何も起きていないときは、静かです。

動いているように見える3日間と、動いていない3日間は、外からは同じ形をしていました。

「エラーが出ていない」を「動いている」と読まないほうがいい、というのが今回の結論です。

コメント

タイトルとURLをコピーしました