Files
Hendrik LiebauandGitHub 84ee9e6916 Unflake "streaming responses cancel inner stream after disconnect" test (#71163)
The
[flakiness](https://app.datadoghq.com/ci/test-runs?query=test_level%3Atest%20env%3Aci%20%40git.repository.id%3Agithub.com%2Fvercel%2Fnext.js%20%40test.service%3Anextjs%20%40test.status%3Afail%20%40test.suite%3A%22streaming%20responses%20cancel%20inner%20stream%20after%20disconnect%22&agg_m=count&agg_m_source=base&agg_t=count&currentTab=overview&eventStack=&fromUser=false&index=citest&start=1720903715972&end=1728679715972&paused=false)
of the test is underreported because due to masked errors, the test
sometimes yields false-positive results.

Due to a slight increase in compilation times for route handlers in
#70897, the test started to fail consistently in that PR.

This PR fixes the flakiness by handling the case where the request might
already be aborted before the response was sent. This leads to the
stream not being consumed, and subsequently its `finished` promise is
never resolved, which finally leads to test timeouts.
2024-10-12 01:59:17 +02:00

58 lines
1.3 KiB
TypeScript

import { IncomingMessage, ServerResponse } from 'http'
import { pipeline } from 'stream'
import { Readable } from '../../readable'
export const config = {
runtime: 'nodejs',
}
let readable: ReturnType<typeof Readable> | undefined
export default async function handler(
req: IncomingMessage,
res: ServerResponse
): Promise<void> {
const url = new URL(req.url!, 'http://localhost/')
if (url.searchParams.has('compile')) {
// The request just wants to trigger compilation.
res.statusCode = 204
res.end()
return
}
// Pages API requests have already consumed the body.
// This is so we don't confuse the request close with the connection close.
const write = url.searchParams.get('write')
if (write) {
const r = (readable = Readable(+write))
res.on('close', () => {
r.abort()
})
return new Promise((resolve) => {
pipeline(r.stream, res, () => {
resolve()
res.end()
})
})
}
// The 2nd request should render the stats. We don't use a query param
// because edge rendering will create a different bundle for that.
const old = readable
if (!old) {
res.statusCode = 500
res.end(
'The streamable from the prime request is unexpectedly not available'
)
return
}
readable = undefined
const i = await old.finished
res.end(`${i}`)
}