Skip to content

refactor(site/src/pages/AgentsPage): use createReconnectingWebSocket in git and workspace watchers#23736

Open
DanielleMaywood wants to merge 3 commits intomainfrom
dm/reconnecting-websocket-refactor
Open

refactor(site/src/pages/AgentsPage): use createReconnectingWebSocket in git and workspace watchers#23736
DanielleMaywood wants to merge 3 commits intomainfrom
dm/reconnecting-websocket-refactor

Conversation

@DanielleMaywood
Copy link
Copy Markdown
Contributor

🤖 This PR was written by Coder Agent on behalf of Danielle Maywood 🤖

Replace hand-rolled reconnection logic in useGitWatcher with the shared
createReconnectingWebSocket utility, and add reconnection support to the
workspace watcher in AgentDetail which previously had none.

Changes

useGitWatcher.ts — Removed reconnectAttemptRef, reconnectTimerRef,
disposedRef, MAX_BACKOFF_MS, and the manual connect() function with its
open/close/error event handlers and backoff timer logic. Replaced with a
single createReconnectingWebSocket call. The socketRef is retained for
bidirectional sendMessage/refresh support, populated via onOpen. Backoff
timing is identical (maxMs: 30_000). All 16 existing tests pass unchanged.

AgentDetail.tsx — Wrapped the workspace watcher useEffect in
createReconnectingWebSocket. Previously, a dropped socket silently killed the
watcher with no reconnection. Now it reconnects with exponential backoff and
invalidates the workspace query on reconnect to fetch fresh data (matching the
pattern the chat list watcher already uses).

Decision log
  • useDesktopConnection left alone: RFB takes socket ownership, custom
    reconnection features (max retries, stable timer, connect timeout) do not
    fit the utility API.
  • Per-chat stream and chat list watcher already use
    createReconnectingWebSocket — no changes needed.
  • The MessageEvent cast in the git watcher message handler is necessary
    because the Closable interface types event handler args as unknown.
  • Stale socket guard (socketRef.current !== socket) kept in the message
    handler as defense-in-depth even though createReconnectingWebSocket
    closes old sockets before creating new ones.

…it and workspace watchers

Replace hand-rolled reconnection logic in useGitWatcher with the shared
createReconnectingWebSocket utility, eliminating ~60 lines of duplicated
backoff/timer/disposal code. Add reconnection to the workspace watcher
in AgentDetail which previously had none — a dropped socket silently
killed the watcher.
@github-actions github-actions bot added the community Pull Requests and issues created by the community. label Mar 27, 2026
@DanielleMaywood DanielleMaywood changed the title refactor(site/pages/AgentsPage): use createReconnectingWebSocket in git and workspace watchers refactor(site/src/pages/AgentsPage): use createReconnectingWebSocket in git and workspace watchers Mar 27, 2026
The setQueryData updater compared prev.latest_build.resources with ===
(referential equality). Since each WebSocket message deserializes fresh
JSON, resources is always a new object, so the check never short-
circuited. Replace with comparisons of the specific agent fields the UI
actually reads: id, status, name, and expanded_directory.
@DanielleMaywood DanielleMaywood marked this pull request as ready for review March 27, 2026 23:47
… onOpen

The Storybook WebSocket mock never fires an 'open' event (stories only
declare message events). The refactored code set socketRef.current in
onOpen, so the message handler's stale socket guard rejected every
message. Move the assignment into the connect factory where the old
code had it, so messages work even when open never fires.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

community Pull Requests and issues created by the community.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant