Skip to content

Resolve #2733: Remove abort listener after synchronous callback throw#2759

Merged
ayden94 merged 1 commit into
mainfrom
issue-2733-remove-abort-listener-sync-throw
Jul 14, 2026
Merged

Resolve #2733: Remove abort listener after synchronous callback throw#2759
ayden94 merged 1 commit into
mainfrom
issue-2733-remove-abort-listener-sync-throw

Conversation

@ayden94

@ayden94 ayden94 commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Summary

Linked context: Closes #2733

raceWithAbort(fn, signal) registered its abort listener before invoking fn() and relied on Promise.resolve(fn()).finally(...) to remove it. When fn() threw synchronously, the throw escaped before Promise.resolve could wrap it, so the finally cleanup never ran and the abort listener leaked on the signal. Repeated failed operations could retain listeners and leaked references.

Changes

  • packages/runtime/src/abort.ts: Convert the fn() invocation into a settled promise via try/catch so a synchronous throw flows through the same finally cleanup that removes the abort listener. Promise.resolve() only wraps an already-produced value; it does not catch a throw emitted while fn() is invoked, so the explicit try/catch is required.
  • packages/runtime/src/abort.test.ts: New regression test suite covering raceWithAbort and createAbortError, including sync-throw listener removal, post-throw abort behavior, and normal resolve/abort paths.
  • packages/runtime/README.md / README.ko.md: Document the behavioral contract that the abort listener is always removed once fn settles, including synchronous throws.
  • .changeset/race-with-abort-remove-listener-sync-throw.md: Patch changeset for @fluojs/runtime because abort helpers are public runtime integration behavior.

Testing

  • pnpm vitest run packages/runtime/src/abort.test.ts — 9 tests passed.
  • pnpm --filter @fluojs/runtime test — 283 tests passed (24 files).
  • pnpm --filter @fluojs/runtime typecheck — passed.
  • pnpm exec biome lint packages/runtime/src/abort.ts packages/runtime/src/abort.test.ts — passed.
  • pnpm verify:public-export-tsdoc — passed (changed mode).
  • pnpm verify:platform-consistency-governance — passed.

Release impact

  • This PR has consumer-visible release impact and includes a changeset.
  • This PR has no consumer-visible release impact.

Patch changeset for @fluojs/runtime: abort helpers are public runtime integration behavior and the listener-leak fix changes cleanup semantics for synchronous-throw callers.

Public export documentation

  • Changed public exports include a source-level summary.
  • Changed exported functions document matching @param / @returns tags where applicable.
  • Source @example blocks and README scenario examples still play complementary roles.

The raceWithAbort TSDoc was extended to document the synchronous-throw cleanup guarantee and the re-throw behavior.

Behavioral contract

  • No documented behavioral contracts were removed without migration notes.
  • New behavioral contracts are documented in the affected package README.
  • Intentional limitations are explicitly stated (not silently removed).
  • Runtime invariants are covered by regression tests.

New behavioral contract: raceWithAbort(fn, signal) always removes its abort listener once fn settles, including when fn throws synchronously before returning a promise. Documented in packages/runtime/README.md and README.ko.md, covered by packages/runtime/src/abort.test.ts.

Platform consistency governance (SSOT)

  • SSOT English/Korean mirror structure remains synchronized for changed governance docs.
  • If platform contract docs changed, companion updates include discoverability/docs index, tooling or CI enforcement, and regression-test evidence.
  • Any package README alignment/conformance claims are backed by the applicable platform harness tests, such as createPlatformConformanceHarness(...) for platform component contracts or createHttpAdapterPortabilityHarness(...) for HTTP adapter portability contracts.

README EN/KO mirrors both received the new behavioral contract bullet. No platform contract docs changed. No platform harness conformance claims were added.

raceWithAbort(fn, signal) registered the abort listener before invoking
fn() and relied on Promise.resolve(fn()).finally(...) to remove it. When
fn() threw synchronously, the throw escaped before Promise.resolve
could wrap it, so the finally cleanup never ran and the listener leaked.

Convert the fn() invocation into a settled promise via try/catch so a
synchronous throw flows through the same finally cleanup that removes
the abort listener. Add regression tests covering sync-throw listener
removal and post-throw abort behavior, and document the contract in the
runtime README (EN/KO).
@ayden94
ayden94 merged commit 65cc3a2 into main Jul 14, 2026
10 checks passed
@ayden94
ayden94 deleted the issue-2733-remove-abort-listener-sync-throw branch July 14, 2026 01:33
This was referenced Jul 14, 2026
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.

[audit][area:foundation] Remove abort listener after synchronous callback throw (priority:p1)

1 participant