defer-run / defer.client

Zero infrastructure Node.js background jobs

Home Page:https://www.defer.run/docs/introduction

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Defer gives an error when running in edge mode in a Next.js app on Vercel

pangolingo opened this issue · comments

I'm attempting to run a Defer function in a Route Handler (formerly called API Route) in my Nextjs app. For performance reasons I marked this API function as using the "edge" runtime instead of the default "nodejs" runtime. This results in an error when I run the function.

Expected behavior:
There are no errors when running a Defer function on the edge runtime.

Actual behavior:
I see an error when running the Defer function. This error occurs in the Next.js app, and the function is never run on Defer's side.

Error: invalid request body: function_name is missing or empty
    at (node_modules/@defer/client/esm/httpClient.js:83:18)
    at (src/app/api/background-job/route.ts:7:17)
    at (node_modules/next/dist/esm/server/future/route-modules/app-route/module.js:189:36) {
  code: 'bad_request'
}

Workarounds:
If I change the route back to using the Node.js runtime, it runs without errors

Observations:
The error message appears to indicate that Defer isn't able to figure out the function's name.

Docs for the edge runtime:
https://nextjs.org/docs/app/building-your-application/routing/route-handlers#edge-and-nodejs-runtimes
https://nextjs.org/docs/app/building-your-application/rendering/edge-and-nodejs-runtimes

Code sample:
This is the Next.js route file - it's pretty simple:

import helloWorld from "@/defer/helloWorld";

export const dynamic = "force-dynamic"; // defaults to auto
export const runtime = "edge"; // 'nodejs' is the default

export async function POST(request: Request) {
  const result = await helloWorld("Dave");

  console.log("result", result);

  return new Response(JSON.stringify({ result }), {
    headers: { "Content-Type": "application/json" },
  });
}

I suspected that maybe Edge was unable to introspect the function to get the name (see docs here: https://nextjs.org/docs/app/api-reference/edge#unsupported-apis).

But checking in the edge runtime REPL it seems to be able to get the function name just fine.

Screen Shot 2024-01-14 at 10 22 30 PM

I enabled debug logs with an ENV variable in Vercel.

When running in the nodejs runtime, I see this log

[defer.run][helloWorld] invoked.

When running in the edge runtime I see this log

[defer.run][] invoked.

Thank you for reporting this to us. It seems that the edge runtime does not support function introspection. We will investigate this issue in more detail and keep you informed.

Could we alter the defer() function to take a string functionName in the options? Or is there other introspection going on besides just the name.

In theory adding a functionName field might resolve 3 problems:

  1. this issue with the edge runtime not supporting introspection
  2. requiring the user to turn off experimental serverMinification in the Nextjs config
  3. ability to use this library with Deno (since you would no longer have to pass the actual function to defer(), you could write the deferred functions in standard Typescript, not Deno code

You are right @pangolingo; your approach would definitely be a good workaround while we make progress on another approach that would conserve our current DX (for example: @defer/client good behave like Prisma client and generates an artifact of functions' mapping)