fix: do not await the release on a cancellation path (#2319 round 25)

`ReadableStream.cancel()` adopts the underlying source's cancel promise,
which is permitted never to settle — so awaiting `releaseBody` while
propagating a cancellation can hang the very thing it was meant to end.
The five exceptional exits in the compat probe loop now start the
release without waiting on it: the release is a courtesy to the
connection pool, and the caller's abort or timeout must reach it
regardless. The two non-exceptional awaits are unchanged.

Same class as the tee teardown in round 24, one file over.

Also moves the `redactUrlQuery` import above
DEFAULT_OAUTH_REQUEST_TIMEOUT_MS's JSDoc, which it had split from the
constant — so hover and API tooling see the doc again.

Verified by mutation: awaiting the release makes the new test time out.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YFnM6RqB4nXqNysgUYmjmq
Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
cliffhall 2026-09-11 08:33:18 -04:00
commit b4c02865e4

View file

@ -578,6 +578,36 @@ describe("probe cancellation (#2319)", () => {
expect(cancels).toHaveBeenCalled();
});
it("does not wait on a cancel that never settles", async () => {
// ⚠️ `ReadableStream.cancel()` adopts the underlying source's cancel
// promise, which is permitted never to settle — so awaiting the release on
// a path that is propagating a cancellation would hang the very thing it
// was meant to end.
const discovery = new Response(
new ReadableStream<Uint8Array>({
start(ctrl) {
ctrl.enqueue(new TextEncoder().encode("not found"));
},
cancel() {
return new Promise<void>(() => {});
},
}),
{ status: 404 },
);
const inner = vi.fn<typeof fetch>((input) =>
String(input) === RFC8414
? Promise.resolve(discovery)
: new Promise<Response>(() => {}),
);
const wrapped = withRfc8414OidcCompat(inner);
const reason = new Error("gone");
// Would hang if the release were awaited; the assertion is that it settles.
await expect(
wrapped(RFC8414, { signal: AbortSignal.abort(reason) }),
).rejects.toBe(reason);
});
it("still falls back to the original response on an ordinary probe failure", async () => {
const inner = vi.fn<typeof fetch>((input) => {
if (String(input) === RFC8414) {