Skip to content

Detect stalled and Hono-swallowed SSE writes (CL-7246) - #617

Merged
TheGreatAxios merged 7 commits into
mainfrom
cl-7246-detect-stalled-sse-write
Sep 4, 2026
Merged

TheGreatAxios merged 7 commits into
mainfrom
cl-7246-detect-stalled-sse-write

Conversation

@TheGreatAxios

@TheGreatAxios TheGreatAxios commented Sep 3, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Hono's StreamingApi.write swallows writer errors inside a bare catch {}, so writeSSE can resolve after a failed write or hang forever on a stalled sink. The workbench SSE bridge treated that as a successful delivery and kept the subscriber alive.

Changes

  • After every writeSSE, treat an errored underlying writer (desiredSize === null), an aborted or closed stream, or a write that never settles within 10s as a failed delivery.
  • Report through reportError, tear down both subscriptions, and close the stream so the client reconnects instead of sitting on a zombie connection.
  • Tests cover the swallowed-writer path and the stall timeout (CL-7246).

https://linear.app/abklabs/issue/CL-7246

Fixes CL-7246

Hono StreamingApi.write never rejects, so a write that looks successful can still have failed or hung. Pin both failure paths before the detection lands.
After every writeSSE, treat an errored writer, aborted or closed stream, or a write that never settles as a failed delivery: report, tear down, and close so a dead client cannot stay subscribed.
Hono close() queues behind an in-flight writer.write, so a stalled
sink never drops the socket. Abort the writer instead, skip reportError
when onAbort already tore down, and apply the same timeout/teardown
path to the presence SSE stream.
Client abort mid-write must not reportError and must still abort the writer.
Skip-report on client abort also skipped dropStream, so Hono close()
waited on the still-in-flight write. Still skip reportError; still
abort the writer on chat and presence streams.
@TheGreatAxios

Copy link
Copy Markdown
Contributor Author

Fixes CL-7246

Aborting a healthy Hono stream errors the body with undefined, which
failed the live share-revocation test on Linux CI. Hung writes still
abort the writer so close() cannot stall behind them.
@linear-code

linear-code Bot commented Sep 4, 2026

Copy link
Copy Markdown

CL-7246

@TheGreatAxios

Copy link
Copy Markdown
Contributor Author

Self-review

Verdict: the stall/swallowed-write detection and teardown logic are correct and well-tested against Hono's real StreamingApi (writer.desiredSize, writer.abort() semantics verified against hono's source in node_modules); ready to merge.

  • Stalled-write detection via writer.desiredSize === null and the write-timeout race — CONFIRMED, verified against Hono's StreamingApi internals (writer = writable.getWriter()); desiredSize === null is spec-accurate for an errored writer. DISMISSED as a concern.
  • Aborting the underlying writer instead of stream.close() on a stall — CONFIRMED, verified this errors the response's pull() read and propagates as a stream error rather than a clean disconnect; already disclosed in the doc comment, and workbench-share-routes.test.ts was updated with a .catch(() => undefined) to account for it. DISMISSED as a concern.
  • Overflow path (MAX_QUEUED_DELIVERIES) now also calls dropHungStream instead of a plain closeStream — DISMISSED: queue overflow is itself caused by a task stuck on a hung write, so routing it through the same stall-teardown path is consistent, not a regression.
  • report-error-ignore on abortUnderlyingWriter's synchronous-throw catch — CONFIRMED correct usage; bun run scripts/checks/report-error.ts shows 0 new findings.
  • Doc comment for bridgeWorkbenchStream had a stray mid-sentence line break ("keeps idle connections alive\nbehind proxies...") — CONFIRMED-FIXED in a follow-up commit.

Tests run (from packages/chat):

  • bun test test/workbench-events.test.ts — 25 pass, 0 fail
  • bun test test/workbench-share-routes.test.ts — 12 pass, 0 fail
  • bun run typecheck — clean
  • bunx eslint src/workbench-events.ts test/workbench-events.test.ts — clean

@TheGreatAxios
TheGreatAxios merged commit 997ee31 into main Sep 4, 2026
7 checks passed
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.

1 participant