-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Open
Labels
Description
Hi Remix!
I noticed that the abort controller on a cloned request is lost if the GC runs between the request and the server response. This can happen if the response body is a ReadableStream and the client interrupts its request in the meantime.
The fetch method of fetch-router clones the initial request with let request = new Request(input, init);.
The following test fails to complete correctly because the signal is lost.
To run the test, be sure to enable the --expose-gc option....
NODE_OPTIONS="--expose-gc" pnpm --filter @remix-run/fetch-router test
it('handle abort signal on cloned request, not finished and garbage collected', async () => {
let router = createRouter()
let aborted = false
router.get('/', async ({ request }) => {
let stream = new ReadableStream({
start(controller) {
// this signal should not be lost after GC !
request.signal.addEventListener('abort', () => {
controller.close()
aborted = true
})
},
})
return new Response(stream)
})
let ac = new AbortController()
let request = new Request('https://remix.run', { signal: ac.signal })
setTimeout(() => {
// force GC (ensure --expose-gc is specified)
global.gc!()
// client cancel the request
ac.abort()
})
let response = await router.fetch(request)
assert.equal(response.status, 200)
// drain the content
await response.arrayBuffer()
assert.equal(aborted, true)
})
})The test works if you comment out global.gc() or if fetch-router use input as request if it is of type Request.
I don't know if this issue is related to: nodejs/undici#4068