Skip to content

fix: remove abort listener after fetch completion#1906

Open
koriyoshi2041 wants to merge 2 commits into
openai:mainfrom
koriyoshi2041:fix-fetch-timeout-abort-listener
Open

fix: remove abort listener after fetch completion#1906
koriyoshi2041 wants to merge 2 commits into
openai:mainfrom
koriyoshi2041:fix-fetch-timeout-abort-listener

Conversation

@koriyoshi2041

Copy link
Copy Markdown

Summary

  • remove the caller signal abort listener when fetchWithTimeout completes
  • add a regression test that verifies the listener is removed after a successful fetch

Fixes #1811.

Tests

  • ./node_modules/.bin/jest tests/index.test.ts -t "removes abort listener after successful fetch" --runInBand
  • ./node_modules/.bin/prettier --check src/client.ts tests/index.test.ts
  • ./node_modules/.bin/eslint src/client.ts tests/index.test.ts

@koriyoshi2041 koriyoshi2041 requested a review from a team as a code owner June 1, 2026 01:09

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ec0c403736

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/client.ts Outdated
return await this.fetch.call(undefined, url, fetchOptions);
} finally {
clearTimeout(timeout);
if (signal) signal.removeEventListener('abort', abort);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep the abort listener until streams finish

For streaming requests (options.stream), fetch resolves as soon as response headers arrive, while the body is consumed later by Stream.fromSSEResponse(response, props.controller, ...) in src/internal/parse.ts. Removing the caller's abort listener in this finally means an external AbortController only cancels up to header receipt; aborting after the stream is returned no longer propagates to the controller that _iterSSEMessages uses to stop the body read, so long-running streams cannot be cancelled via the original request signal.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, good catch. I updated the PR so streaming requests keep the caller abort listener after fetch resolves, which preserves external abort propagation to the stream controller after headers are received.

Added a regression test for the streaming case and reran:

  • ./node_modules/.bin/jest tests/index.test.ts -t 'abort listener' --runInBand

  • ./node_modules/.bin/prettier --check src/client.ts tests/index.test.ts

  • ./node_modules/.bin/eslint src/client.ts tests/index.test.ts

  • git diff --check

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fetchWithTimeout does not remove abort event listener on successful completion, preventing process exit on Deno

1 participant