You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
2.0: Enforce event-stream ownership, cleanup, and diagnostics #36445
The generated Promise SSE client cancels its ReadableStream reader after a parser failure, but under Bun 1.3.14 that does not reliably close the underlying HTTP response. The TUI reconnect loop can open a replacement while the server retains the previous response, EventV2.liveBounded listener, and queue.
A real-socket reproduction sends malformed SSE while keeping the response open. The client rejects with MalformedResponse, but the server still reports one active response after cleanup.
Without diagnostics, active response count, event-bus subscriber count, and serialization volume are invisible until CPU and memory become pathological.
Goal
Guarantee one active event stream per client owner, prompt resource release on failure/teardown, and enough bounded diagnostics to identify leaks.
Requirements
Define ownership for one mounted TUI and one event-stream generation.
Abort or fully dispose the previous transport before opening its replacement.
Ensure HTTP response finalization removes the event listener and shuts down its queue.
Handle malformed data, oversized events, transport failures, server restarts, and consumer exceptions.
Add retry backoff/jitter where synchronized clients would otherwise reconnect in phase.
Expose content-free diagnostics for active streams/subscribers, opens/closes, serialized event counts/bytes, overflows, and reconnect reasons.
Acceptance criteria
One mounted TUI has exactly one active stream and zero after teardown.
Repeated failure/reconnect cycles never exceed one active stream per TUI.
Eleven TUI clients produce exactly eleven active streams, not an accumulating count.
Cancelling a real network client closes the server response and returns listener count to baseline.
Each event ID is handled at most once per TUI generation.
Diagnostics expose leaked/overlapping subscriptions without logging payloads.
I reproduced the malformed-SSE cleanup leak on current dev with a real Bun 1.3.14 HTTP socket: the Promise client rejects with MalformedResponse, but the server response remains open after reader.cancel(). There is no overlapping open PR touching packages/httpapi-codegen/src/index.ts or the generated Promise client. I can take a focused first slice that gives each SSE iterator an internal abort controller, aborts the fetch transport on parser exit, regenerates the client, and adds a real-socket regression proving server-side close. This would address transport cleanup only, not close the broader ownership/diagnostics issue. Is that split acceptable, and should it get a focused child issue for the issue-first requirement?
Follow-up after prototyping: an internal fetch AbortController plus reader.cancel() still does not close the server response on Bun 1.3.14 in the real-socket regression. The effective mitigation therefore needs the server-side IncomingMessage.aborted -> ServerResponse.destroy() bridge, which overlaps the active claim on #36311. I am withdrawing this client-only slice rather than opening a duplicate or ineffective PR.
Partly done: the root server leak (#36311) was fixed by the Bun upgrade, and the client now shares event streams (packages/client/src/shared-events.ts) and detects stalls (#47571). Stream diagnostics, reconnect backoff with jitter and aborting the transport on parser failure weren't added; #37585 was closed unmerged. Closing this tracker.
Activity
HOYALIM commentedon Jul 13, 2026
I reproduced the malformed-SSE cleanup leak on current
devwith a real Bun 1.3.14 HTTP socket: the Promise client rejects withMalformedResponse, but the server response remains open afterreader.cancel(). There is no overlapping open PR touchingpackages/httpapi-codegen/src/index.tsor the generated Promise client. I can take a focused first slice that gives each SSE iterator an internal abort controller, aborts the fetch transport on parser exit, regenerates the client, and adds a real-socket regression proving server-side close. This would address transport cleanup only, not close the broader ownership/diagnostics issue. Is that split acceptable, and should it get a focused child issue for the issue-first requirement?HOYALIM commentedon Jul 13, 2026
Follow-up after prototyping: an internal fetch
AbortControllerplusreader.cancel()still does not close the server response on Bun 1.3.14 in the real-socket regression. The effective mitigation therefore needs the server-sideIncomingMessage.aborted->ServerResponse.destroy()bridge, which overlaps the active claim on #36311. I am withdrawing this client-only slice rather than opening a duplicate or ineffective PR.neriousy commentedon Oct 21, 2026
Partly done: the root server leak (#36311) was fixed by the Bun upgrade, and the client now shares event streams (packages/client/src/shared-events.ts) and detects stalls (#47571). Stream diagnostics, reconnect backoff with jitter and aborting the transport on parser failure weren't added; #37585 was closed unmerged. Closing this tracker.