Files
Janka UrygaandGitHub d538cfb740 fix: after(callback) called after response end (#94974)
Fixes a bug where if `after(callback)`was called after the response
ended, and no `after(callback)` calls occurred earlier, the callback
would never run.

Implementation-wise, what happens is:
1. when the first callback is scheduled, we do `runCallbacksOnClose()`,
which waits until `onClose` fires and starts the callback queue
2. but if no `after(callback)` calls occurred before the response ended,
then by the time we got to `runCallbacksOnClose()`, `onClose` has
already fired, so we'd wait forever

We now start listening for `onClose` when the context is initialized and
track the state (`isRequestClosed`), which avoids this.

I also did another drive-by fix here: if we only had `after(promise)`
calls, we wouldn't switch the workUnitStore's phase to `'after'`,
because we were only doing that in the `after(callback)` codepath. This
is relevant in #94964 which fixes some bugs around `after(promise)`.
2026-06-19 20:55:10 +02:00

28 lines
905 B
JavaScript

import { after, connection } from 'next/server'
import { cliLog } from '../../../utils/log'
export default async function Page() {
await connection()
// This test checks if `after` callbacks scheduled from `after(promise)` are executed if
// - the promise resolves after the response ended
// - no `after(callback)` calls occurred before the response ended
// We had a bug where the after callback queue wouldn't start if no `after(callback)` calls occured during the response,
// so the callback scheduled from the promise would never run.
const promise = (async () => {
// hackily wait for the response to finish
await new Promise((resolve) => setTimeout(resolve, 500))
after(() => {
cliLog({
source: '[page] /nested-after-from-slow-promise',
})
})
})()
after(promise)
return <div>Page with nested after() called from a slow promise</div>
}