Skip to content

fix(sse): close the event stream on pagehide and reconnect on bfcache restore - #434

Merged
chriswritescode-dev merged 1 commit into
mainfrom
fix/sse-close-on-pagehide
Oct 15, 2026
Merged

chriswritescode-dev merged 1 commit into
mainfrom
fix/sse-close-on-pagehide

Conversation

@chriswritescode-dev

@chriswritescode-dev chriswritescode-dev commented Oct 15, 2026 •

Copy link
Copy Markdown
Owner

Summary

Pages could hang on loading skeletons for 15s or more after a few full-page navigations over plain HTTP.

The app opens one EventSource to /api/sse/stream and never closed it when the page was hidden. Chrome puts the page into the back/forward cache on full-document navigations (address bar, bookmarks, back/forward, the /login redirects), and the cached page's stream stayed open. /api/sse/status reported 4-5 live clients for a single tab. Over HTTP/1.1 Chrome allows only 6 connections per host, so after about 5 navigations the next page load waited for a connection to free up. HTTPS behind an HTTP/2 proxy hides the problem; plain http://host:port access does not.

Fix

OpenCodeEventStream registers window listeners in the browser:

  • pagehide closes the live connection through the existing disconnectConnectionOnly(). Subscribers and directory ref counts are kept, and directories are re-queued as pending.
  • pageshow with persisted: true (restored from the back/forward cache) calls the existing reconnect(), which resubscribes the pending directories and notifies status like any other reconnect.

Type of Change

  • Bug fix
  • New feature
  • Refactor
  • Documentation

Checklist

  • Code follows project style (no comments, named imports)
  • TypeScript types are properly defined
  • Tests added/updated (80% coverage target)
  • pnpm lint:frontend passes locally
  • Frontend typecheck passes locally

Tests

frontend/src/lib/opencode-event-stream/__tests__/openCodeEventStream.test.ts:

  • pagehide closes the active connection and does not schedule a reconnect.
  • pageshow with persisted: true opens a new connection carrying the subscribed directories.
  • pageshow with persisted: false opens no extra connection.

Validation

  • pnpm --filter frontend exec vitest run src/lib/opencode-event-stream src/hooks/useSSE.test.tsx: 38 passed
  • pnpm --filter frontend exec tsc --noEmit -p . and pnpm lint:frontend: clean
  • Manual check in Chrome against a production build, 15 full-page navigations:
    • Before: /api/sse/status climbed to 4-5 clients and navigations timed out after 15s.
    • After: every page entered the back/forward cache, the server held exactly 1 client throughout, and each load took about 85ms. Going back restored the cached page and reconnected its stream, still with 1 client.

Summary by CodeRabbit

  • Bug Fixes
    • Event stream connections now close when a page is hidden, preventing reconnect attempts during the following 60 seconds.
    • When a page is restored from the browser’s back-forward cache, the event stream reconnects to its subscribed directories. Other page-show events do not trigger a reconnect.

@coderabbitai

coderabbitai Bot commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Essentials
  • Run ID: c6b435c8-f6b6-4430-8669-1d53a2e015a5
📥 Commits

Reviewing files that changed from the base of the PR and between ef7ff52 and cd2f6d4.

📒 Files selected for processing: 2
  • frontend/src/lib/opencode-event-stream/__tests__/openCodeEventStream.test.ts
  • frontend/src/lib/opencode-event-stream/openCodeEventStream.ts

Included review availability: This review used your included allowance. Your plan provides up to 5 included reviews per hour; 2 remain after this review.

📝 Walkthrough

OpenCodeEventStream now disconnects its active connection on pagehide and reconnects on persisted pageshow events. Tests cover disconnect timing, reconnect URLs, and non-persisted pageshow events.

Changes: Page lifecycle connection handling

Layer / File(s) Summary
Lifecycle disconnect and reconnect
frontend/src/lib/opencode-event-stream/openCodeEventStream.ts, frontend/src/lib/opencode-event-stream/__tests__/openCodeEventStream.test.ts
The stream disconnects on pagehide and reconnects on pageshow only when persisted is true. Tests verify that it does not reopen during the following 60 seconds after pagehide, that persisted pageshow reconnects with subscribed directories, and that non-persisted pageshow does not reconnect.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Merge Risk: ⚪ Minimal · up to cd2f6

The stream closes on pagehide and reconnects when a page is restored from the back/forward cache. No actionable merge risk remains.

Pre-merge checks: Passed 5
Check name Status Explanation
Title check Passed The title clearly identifies the SSE lifecycle fix: closing the stream on pagehide and reconnecting after bfcache restoration.
Description check Passed The description explains the problem, implementation, tests, validation results, and type of change. It addresses the required template sections and provides relevant technical context.
Docstring Coverage Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 2…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@chriswritescode-dev
chriswritescode-dev merged commit be874ee into main Oct 15, 2026
2 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