Skip to content

Users see the browser reload itself when the WebSocket drops — make reconnection silent, then remove the socket #501

Description

@Robbie1977

The problem

Any connection blip (Wi-Fi change, laptop sleep, phone backgrounded) or a backend recycle makes the Geppetto browser reload the page, losing colours, visibility, slice position and layout. Users read this as "VFB is buggy". The socket is also the transport for all bulk data (term info, query results, OBJ/SWC), which is where the size caps and timeouts we keep tuning come from.

Where the reloads come from (geppetto-client VFBv2.3.8.9, geppetto-vfb v2.2.9.8)

  1. Retry budget is seconds, not minutes. MessageSocket.js retries at a fixed 5 s with reconnectionLimit: 10, but each abnormal close spends two attempts (onclose line 217 and reconnect() line 281), so a drop gets ~5 retries over ~25 s and no backoff. A closed lid exhausts it.
  2. VFBMain reloads immediately, so the 10 s dialog from #1728 never shows. components/VFBMain.js:2112–2144 listens for Websocket_disconnected and calls window.location.reload() at line 2133 when attempts >= 2. reconnect() fires that event in the same tick as it opens the auto-dismissing dialog. Net effect of geppetto-vfb #1728: fewer dialogs, same number of reloads. Also an unconditional reload on close code 1002 (MessageSocket.js:211).
  3. Resume only works on the same JVM inside 5 minutes. WebsocketConnection.java:259–270 looks the lost connection id up in ConnectionsManager (5 min / 32-entry retention, from #458). A redeploy, OOM restart or HAProxy redispatch to the other replica returns RECONNECTION_ERROR, which GEPPETTO.GlobalHandler.js:102–113 turns into a reload. The sticky cookie is supposed to route the resume back to the same replica, but containers are recycled often enough (scale: 2, recreateOnQuorum quorum:1, OOM restarts, redeploys) that the JVM holding the session is frequently gone. Resume on the old server can only ever be a fast path; the client must be able to start the session again on whichever server answers.
  4. Nothing is queued during a reconnect. send() silently drops every command while RECONNECTING (MessageSocket.js:307–314); waitForConnection drops when readyState > 1; pending callbacks are never failed. Even a successful resume can leave a term half-loaded with the spinner stopped.
  5. Bulk data over the socket. Term info (fetch_variable), query results (run_query, 66 MB page-0 messages per Geppetto frontend accumulates memory until containers OOM and recycle #458) and OBJ/SWC bodies (resolve_import_value, parsed from the model JSON at ThreeDEngine.js:1038) all travel over the socket. Hence MAX_OBJ_BYTES 150 MB + skeleton fallback, VFB_WS_SEND_TIMEOUT_MS 300 s and per-message gzip from #455 / geppetto-vfb #1714, and the decimation work in #456. Only the stack-viewer tiles, Solr, the pdb graph/circuit browsers and the ROI tree (already fetch to v3-cached) bypass it.
  6. Reload recovers only the URL. id, i and q are restored (VFBMain.js:1816–1870); colours, visibility and layout are not.

Related: #328 (new TermInfo design), #403 (query caching), virtual-fly-brain #7 (v3 testing epic).

Options considered

  • A. Silent reconnect in v2. Backoff + long budget + retry on online/visibilitychange; queue and replay commands; treat a new server as the normal case: try reconnect once, and on RECONNECTION_ERROR rebuild the session in place on the new server (reload the project, re-request the ids the Redux store already holds, re-apply colour/visibility, replay the queue) with a non-blocking toast; reload only if the in-place rebuild fails. The store and URL already hold everything needed, so no server-side state has to survive. Days of work; caps remain, but which JVM serves the session stops mattering.
  • B. Bypass the socket for data in v2. Meshes/SWC by URL from the get_term_info image records, paged run_query over HTTP from v3-cached, term info rendered from VFBquery JSON in JS (port of the subset of VFBProcessTermInfoVFBqueryJson the panel uses). After that the socket carries nothing and can go. Weeks; it is a rewrite of v2's data layer in a codebase we intend to replace. Only the mesh half is cheap.
  • C. Single-page term view on the v3 data layer. virtual-fly-brain already has no socket: plain fetch for term info and queries, meshes by URL, ?id=/?i= state. Its layout is a v2 clone that users want replaced anyway (Codex-style scrolling term page, 3D as an optional widget — grant Figure 3). Keep its data layer, Redux slices, URL middleware and stack viewer; drop the flexlayout shell, the Flask wrapper (talk to v3-cached directly) and the MUI v4 code. Months, and a design pass first.
  • D. Deploy what is built and stop. v2.2.9.1 and v2.2.9.0 are released, not deployed. Removes the blocking dialog and the memory ratchet; does not reduce reloads (point 2).

Proposed way forward

  • Phase 0 (now): deploy geppetto-vfb v2.2.9.1 to production; pull a baseline of the existing GA websocket-disconnect events (disconnected, reconnect-attempt:N, reconnect-failed-reloading) for the preceding weeks so Phase 1 can be measured against it.
  • Phase 1 (1–2 weeks, geppetto-client VFBv2.3.8.10 + geppetto-vfb): option A. Acceptance: restart the backend under a loaded scene, and separately force the resume onto the other replica (drop the sticky cookie); in both cases the page recovers with ids, colours and visibility intact, no reload; reconnect-failed-reloading near zero against the baseline over a week of production traffic.
  • Phase 2 (optional, 1–2 weeks): client-side mesh/SWC loading by URL in v2 only (finishes Large neuron meshes never render: OBJ is streamed through the websocket instead of loaded by the client #455, makes Decimate published neuron meshes and serve them compressed #456 a pure asset-pipeline job). Skip the term-info and query halves of B.
  • Phase 3 (design now, build after the grant decision): the single-page term view on the v3 data layer. Start with a design review of Figure 3 + Codex with Kit/Philipp/David, then a thin prototype rendering get_term_info for one class and one individual as a scrolling page with a lazy 3D widget. Decide then whether virtual-fly-brain is evolved in place or a new app imports its data layer.

Open decisions: whether Phase 2 happens at all; evolve vs restart for Phase 3; Neuroglancer vs the Geppetto canvas as the 3D widget; who owns the design pass.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions