Automattic / Automattic/gutenberg-sync-engines
Stop polling while editing alone; notice a second person through the heartbeat WordPress already sends
- Dominant language
- JavaScript
- Stars
- 2
- Forks
- 0
- Avg merge
- 11h 22m
- Merged PRs (30d)
- 49
Description
## What happens now
With collaboration turned on, a person editing a post alone still asks the server for updates every 4 seconds, for as long as the tab is open. The code is explicit that these requests exist for one reason only: to notice when a second person arrives. Editing alone is the overwhelmingly common case, so on a busy site — or across a hosting fleet — almost all of the plugin's background traffic is solo editors waiting for company that never comes. One open, focused editor tab makes about 21,600 of these requests per day (a backgrounded tab about 3,500). For comparison, the heartbeat WordPress itself sends from every editor screen — with or without this plugin — is one request every 15 seconds, about 5,800 per day.
## Example
1. Activate the plugin and turn collaboration on.
2. Open any post in the editor, alone, and open the browser's developer tools → Network, filtered to `wp-sync`.
3. Leave the tab focused and do nothing.
**What you see:** a `/wp-sync/v1/updates` request every 4 seconds, indefinitely, each returning nothing new.
**What you expected:** no background requests beyond the heartbeat WordPress already sends, until a second person actually opens the same post.
## What should happen instead
While one person edits alone, the plugin should send nothing of its own. The "did someone join me?" question should ride the heartbeat WordPress already sends from every editor screen: the server answers it from what it already knows, and the moment a second person opens the post, both editors switch into live collaboration — from then on everything works exactly as today. Editing alone would then cost a host nothing beyond what WordPress already costs, and the plugin's traffic would scale with actual collaboration instead of with open tabs.
## How we will know it is done
1. Repeat the example: with the tab focused and idle for two minutes, the Network panel shows zero `/wp-sync/` requests — only the heartbeat.
2. Open the same post as a second user in another window: within one heartbeat cycle both windows begin syncing, and the two-window e2e suite (`npm run test:e2e`) still passes unchanged.
3. Text typed by the first person before the second person arrived is present in both windows once they connect — nothing typed during the switchover is lost. Needs a test: a two-window spec where window B joins late and window A typed during the quiet period.
The host benchmark (`npm run bench`) gives the before/after at a glance: today a solo idle tab shows the polling cadence in its idle table; after this change it should collapse to the heartbeat baseline.
## Notes for whoever picks this up
- The solo cadence and its stated purpose: `src/providers/http-polling/config.ts` — `DEFAULT_POLLING_INTERVAL_IN_MS = 4000`, with the comment "Solo polling only watches for a collaborator arriving." Background tabs poll at 25 s (`POLLING_INTERVAL_BACKGROUND_TAB_IN_MS`), deliberately under the server's 30 s awareness timeout — a redesign must keep the switch-on path compatible with that timeout (a first poll after a long quiet period must not read as a reconnect of a timed-out peer).
- The heartbeat channel: core's `wp.heartbeat` runs on every edit screen at 15 s while focused (it maintains the classic post lock via `wp_refresh_post_lock`) and backs off when hidden. Server side, a `heartbeat_received` filter can answer "is anyone else in this post's collaboration state?" cheaply — use a non-creating lookup (`peek_room_engine`; the storage API's ordinary room lookup CREATES storage posts, see the gotcha in AGENTS.md). Client side, a `heartbeat.tick` listener can start the sync session.
- Only the FIRST person needs the nudge. The second person's editor can start the session immediately on load — the post is already open elsewhere, which the lock/heartbeat data already shows — and their session start writes the presence the first person's next heartbeat answer reads.
- Edits made while alone, before the switch, must survive it. The engines already reconcile a client joining a post that has existing history (that is every second joiner today); the new wrinkle is the first person folding their own not-yet-synced edits into a session someone else started. The closest existing machinery is each engine's join/bootstrap path and, for intent-log, the buffered pre-init tree recovery described in AGENTS.md.
- Scope boundary: session start lives partly in the framework (`@wordpress/sync`'s createSyncManager and the provider SPI, vendored under `gutenberg/`). If gating session creation needs framework changes, that part is upstream/human-owned; the plugin-side pieces (provider gating, the heartbeat filter and listener) belong here. Flag the split early rather than discovering it late.
- All three transports benefit, because the gate sits above transport choice: short polling stops its 4 s solo requests, long polling stops holding a PHP worker for a solo watcher, and websocket stops keeping a per-tab daemon connection nobody is using.
- Related dials and reports: the Settings → Collaboration polling interval governs the with-collaborators cadence and is untouched by this; the host benchmark's idle table and its requests-per-day arithmetic are the measurement to quote in the PR.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.