Skip to content

feat(sync-service): add WebSocket wake multiplexing#4701

Open
icehaunter wants to merge 1 commit into
mainfrom
codex/websocket-wake-multiplexing
Open

feat(sync-service): add WebSocket wake multiplexing#4701
icehaunter wants to merge 1 commit into
mainfrom
codex/websocket-wake-multiplexing

Conversation

@icehaunter

Copy link
Copy Markdown
Contributor

Closes #4700.

Motivation

Each ordinary live shape request keeps an HTTP request process and its closure state alive for the full long-poll interval. At roughly 50–80 KB per reader, 200,000 mostly-silent readers can retain around 10 GB while only a small fraction receive changes.

This adds an internal transport for multiplexing only the waiting portion of those requests. Shape rows and changelog bodies remain on the existing HTTP endpoint, preserving the public client contract, caching, streaming, and proxy authorization model.

What changed

  • Adds authenticated GET /v1/shape/multiplex using WebSocket subprotocol electric.shape-multiplex.v1.
  • Accepts dynamic watch and unwatch frames keyed by an opaque request id, existing handle, concrete live offset, and prior raw Electric cursor.
  • Coalesces Registry subscriptions per shape handle while retaining independent logical deadlines per watch.
  • Uses subscribe-then-head rechecking so a change racing with registration wakes immediately; offset regressions and missing/rotated handles wake the proxy for a direct HTTP refetch.
  • Supports ordinary numeric offsets and the canonical 0_inf quiet-shape offset, while rejecting snapshot and other special offsets.
  • Sends only wake/rotation signals over the socket when data may exist. On Electric's normal long-poll deadline it emits a terminal no_change envelope built through the existing HTTP response-header machinery, including the advancing cursor, cache policy, ETag, handle, offset, and up-to-date body.
  • Rejects upgrades unless this is the active Electric instance and periodically rechecks availability, closing established sockets with 1012 after ownership/activity loss.
  • Exposes an optional live availability_guard for embedded deployments such as Electric Cloud.
  • Uses a cheap handle-existence/latest-offset lookup rather than resolving full shape definitions on the hot watch path.
  • Documents the internal protocol and adds a sync-service changeset.

Protocol and operational decisions

Electric owns every logical deadline. There is no timeout HTTP probe: after a terminal no-change response, the unchanged client naturally sends its next request, whose new watch performs the same subscribe-then-head check.

The endpoint intentionally does not send shape data, expose a new public client API, or move authentication into Electric. It uses the same service-secret protection as the shape endpoint and is intended for trusted proxies.

@codecov

codecov Bot commented Jul 13, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 60.04%. Comparing base (3ef7614) to head (18c84e0).
⚠️ Report is 1 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4701      +/-   ##
==========================================
- Coverage   60.20%   60.04%   -0.16%     
==========================================
  Files         412      397      -15     
  Lines       44396    43766     -630     
  Branches    12586    12585       -1     
==========================================
- Hits        26727    26279     -448     
+ Misses      17587    17406     -181     
+ Partials       82       81       -1     
Flag Coverage Δ
electric-telemetry ?
elixir ?
packages/agents 72.64% <ø> (ø)
packages/agents-mcp 77.70% <ø> (ø)
packages/agents-mobile 80.67% <ø> (ø)
packages/agents-runtime 83.72% <ø> (ø)
packages/agents-server 75.63% <ø> (-0.02%) ⬇️
packages/agents-server-ui 8.32% <ø> (ø)
packages/electric-ax 51.06% <ø> (ø)
packages/experimental 87.73% <ø> (ø)
packages/react-hooks 86.48% <ø> (ø)
packages/start 82.83% <ø> (ø)
packages/typescript-client 91.89% <ø> (+0.11%) ⬆️
packages/y-electric 56.05% <ø> (ø)
typescript 60.04% <ø> (ø)
unit-tests 60.04% <ø> (-0.16%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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.

RFC: Websocket wake multiplexing

1 participant