From 4d1613d049037b2b39295a9479c9f8c9a12df907 Mon Sep 17 00:00:00 2001 From: Janka Uryga Date: Wed, 11 Dec 2024 20:58:52 +0100 Subject: [PATCH] docs: supporting `after` for providers (#73743) Co-authored-by: Delba de Oliveira <32464864+delbaoliveira@users.noreply.github.com> Co-authored-by: Lee Robinson --- .../10-deploying/index.mdx | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/docs/01-app/02-building-your-application/10-deploying/index.mdx b/docs/01-app/02-building-your-application/10-deploying/index.mdx index 7452831a0b594..d8dcfec3536a5 100644 --- a/docs/01-app/02-building-your-application/10-deploying/index.mdx +++ b/docs/01-app/02-building-your-application/10-deploying/index.mdx @@ -297,6 +297,67 @@ If you don't need a mix of both static and dynamic components, you can make your + + +### `after` + +[`after`](/docs/app/api-reference/functions/after) is fully supported when self-hosting with `next start`. + +When stopping the server, ensure a graceful shutdown by sending `SIGINT` or `SIGTERM` signals and waiting. This allows the Next.js server to wait until after pending callback functions or promises used inside `after` have finished. + +If you want to use `after` on custom infrastructure, check your provider documentation to view support for `after`. + +
+ Reference: supporting `after` for serverless platforms + Using `after` in a serverless context requires waiting for asynchronous tasks to finish after the response has been sent. In Next.js and Vercel, this is achieved using a primitive called `waitUntil(promise)`, which extends the lifetime of a serverless invocation until all promises passed to [`waitUntil`](https://vercel.com/docs/functions/functions-api-reference#waituntil) have settled. + + If you want your users to be able to run `after`, you will have to provide your implementation of `waitUntil` that behaves in an analogous way. + + When `after` is called, Next.js will access `waitUntil` like this: + + ```jsx + const RequestContext = globalThis[Symbol.for('@next/request-context')] + const contextValue = RequestContext?.get() + const waitUntil = context?.waitUntil + ``` + + Which means that `globalThis[Symbol.for('@next/request-context')]` is expected to contain an object like this: + + ```tsx + type NextRequestContext = { + get(): NextRequestContextValue | undefined + } + + type NextRequestContextValue = { + waitUntil?: (promise: Promise) => void + } + ``` + + Here is an example of the implementation. + + ```tsx + import { AsyncLocalStorage } from 'node:async_hooks' + + const RequestContextStorage = new AsyncLocalStorage() + + // Define and inject the accessor that next.js will use + const RequestContext: NextRequestContext = { + get() { + return RequestContextStorage.getStore() + }, + } + globalThis[Symbol.for('@next/request-context')] = RequestContext + + const handler = (req, res) => { + const contextValue = { waitUntil: YOUR_WAITUNTIL } + // Provide the value + return RequestContextStorage.run(contextValue, () => nextJsHandler(req, res)) + } + ``` +
+ +
+ ## Manual Graceful Shutdowns