defer.client icon indicating copy to clipboard operation
defer.client copied to clipboard

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

Open pangolingo opened this issue 1 year ago • 5 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" },
  });
}

pangolingo avatar Jan 15 '24 04:01 pangolingo

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

pangolingo avatar Jan 15 '24 04:01 pangolingo

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.

pangolingo avatar Jan 15 '24 04:01 pangolingo

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.

gearnode avatar Jan 15 '24 05:01 gearnode

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

pangolingo avatar Jan 16 '24 14:01 pangolingo

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)

charlypoly avatar Jan 19 '24 13:01 charlypoly