Skip to content

Commit

Permalink
always check for platform-provided 'waitUntil' before defaulting to a…
Browse files Browse the repository at this point in the history
… noop
  • Loading branch information
lubieowoce committed May 23, 2024
1 parent 05e6b82 commit 58d1519
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 24 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
export type WaitUntil = (promise: Promise<any>) => void

export function getBuiltinWaitUntil(): WaitUntil | undefined {
export function getBuiltinRequestContext():
| BuiltinRequestContextValue
| undefined {
const _globalThis = globalThis as GlobalThisWithRequestContext
const ctx =
_globalThis[NEXT_REQUEST_CONTEXT_SYMBOL] ??
_globalThis[VERCEL_REQUEST_CONTEXT_SYMBOL]
return ctx?.get()?.waitUntil
return ctx?.get()
}

/** This should be considered unstable until `unstable_after` is stablized. */
Expand All @@ -16,12 +16,16 @@ const NEXT_REQUEST_CONTEXT_SYMBOL = Symbol.for('@next/request-context')
const VERCEL_REQUEST_CONTEXT_SYMBOL = Symbol.for('@vercel/request-context')

type GlobalThisWithRequestContext = typeof globalThis & {
[NEXT_REQUEST_CONTEXT_SYMBOL]?: RequestContext
[NEXT_REQUEST_CONTEXT_SYMBOL]?: BuiltinRequestContext
/** @deprecated */
[VERCEL_REQUEST_CONTEXT_SYMBOL]?: RequestContext
[VERCEL_REQUEST_CONTEXT_SYMBOL]?: BuiltinRequestContext
}

/** This should be considered unstable until `unstable_after` is stablized. */
type RequestContext = {
get(): { waitUntil: WaitUntil } | undefined
/** A request context provided by the platform.
* It should be considered unstable until `unstable_after` is stablized. */
export type BuiltinRequestContext = {
get(): BuiltinRequestContextValue | undefined
}

export type BuiltinRequestContextValue = { waitUntil?: WaitUntil }
export type WaitUntil = (promise: Promise<any>) => void
45 changes: 30 additions & 15 deletions packages/next/src/server/base-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,10 @@ import type { DeepReadonly } from '../shared/lib/deep-readonly'
import { isNodeNextRequest, isNodeNextResponse } from './base-http/helpers'
import { patchSetHeaderWithCookieSupport } from './lib/patch-set-header'
import { checkIsAppPPREnabled } from './lib/experimental/ppr'
import { getBuiltinWaitUntil } from './after/wait-until-builtin'
import {
getBuiltinRequestContext,
type WaitUntil,
} from './after/wait-until-builtin'

export type FindComponentsResult = {
components: LoadComponentsReturnType
Expand Down Expand Up @@ -1667,24 +1670,36 @@ export default abstract class Server<
)
}

private getWaitUntil() {
const useBuiltinWaitUntil =
process.env.NEXT_RUNTIME === 'edge' || this.minimalMode
private getWaitUntil(): WaitUntil | undefined {
const builtinRequestContext = getBuiltinRequestContext()
if (builtinRequestContext) {
// the platform provided a request context.
// use the `waitUntil` from there, whether actually present or not --
// if not present, `unstable_after` will error.
return builtinRequestContext.waitUntil
}

let waitUntil = useBuiltinWaitUntil ? getBuiltinWaitUntil() : undefined
if (process.env.__NEXT_TEST_MODE) {
// we're in a test, use a no-op.
return Server.noopWaitUntil
}

if (!waitUntil) {
// if we're not running in a serverless environment,
// we don't actually need waitUntil -- the server will stay alive anyway.
// the only thing we want to do is prevent unhandled rejections.
waitUntil = function noopWaitUntil(promise) {
promise.catch((err: unknown) => {
console.error(err)
})
}
if (this.minimalMode || process.env.NEXT_RUNTIME === 'edge') {
// we're built for a serverless environment, and `waitUntil` is not available,
// but using a noop would likely lead to incorrect behavior,
// because we have no way of keeping the invocation alive.
// return nothing, and `unstable_after` will error if used.
return undefined
}

return waitUntil
// we're in `next start` or `next dev`. noop is fine for both.
return Server.noopWaitUntil
}

private static noopWaitUntil(promise: Promise<any>) {
promise.catch((err: unknown) => {
console.error(err)
})
}

private async renderImpl(
Expand Down

0 comments on commit 58d1519

Please sign in to comment.