y-partyserver: Hibernation support & awareness fix#341
Open
threepointone wants to merge 5 commits intomainfrom
Open
y-partyserver: Hibernation support & awareness fix#341threepointone wants to merge 5 commits intomainfrom
threepointone wants to merge 5 commits intomainfrom
Conversation
Add a comprehensive test suite and related configs for y-partyserver (unit + integration), including global test setup that spawns wrangler dev, Vitest configs, a wrangler integration config, TS test tsconfig, and many test files (index.test.ts, integration.test.ts, worker.ts, global-setup.ts, etc.). Update package.json metadata and scripts (add test, test:integration, check:test), adjust files/peerDependencies/devDependencies ordering. Fix a bug in YProvider where a trailing slash on the host was not being stripped (assign sliced value back to host). Narrow YServer.onLoad return type to Promise<YDoc | void> to allow returning a Y.Doc from onLoad. Overall this change wires up end-to-end and unit testing infrastructure and includes small API/bug fixes to support tests.
Refactor Y server to support Cloudflare Workers hibernation: remove in-memory conn map and persist per-connection awareness client IDs via connection.state so tracking survives hibernation. Switch broadcasting to use getConnections(), add durable handling for sync and awareness messages, clear stale awareness meta on disconnect, and bump awareness clock on reconnect so remote clients accept re-propagated states. Add debounced persistence and robust connection handling, plus extensive hibernation/integration tests, a Wrangler test harness, and vitest/tsconfig additions. Also update package manifests/workspaces and bump partysocket/partyserver dependency pins.
Prevent periodic awareness heartbeats from generating network traffic and enable client-driven re-sync after DO hibernation. Changes include: - Provider: stop sending clock-only awareness renewals by listening to awareness 'change' (not 'update') and clear the awareness _checkInterval instead of using a built-in check loop; removed related reconnect timeout and local interval handling. - Server: clear WSSharedDoc awareness _checkInterval and, on YServer start, send a sync step 1 to all surviving connections so clients re-sync their full state after hibernation wake-up. - Fixtures/worker: add YHibernateTracker Durable Object (and namespace) to track onStart counts via storage and expose onRequest for tests; expose MonacoServer subclass enabling hibernate. - Tests: add hibernation and awareness tests to verify onStart re-sync behavior, multi-client convergence after restart, new-client re-sync, and suppression of clock-only heartbeats / absence of auto-removal. - Integration config: register YHibernateTracker for SQLite migration. These changes are intended to allow Durable Object hibernation (by avoiding periodic awareness traffic) while ensuring state is re-synchronized from surviving connections after a wake-up.
Add a changeset and update server startup to address Yjs Durable Object hibernation and awareness issues. Key changes: - Add .changeset/hibernation-awareness-fix.md describing fixes for server and provider behavior around hibernation and awareness propagation. - Server: persist connection state instead of in-memory Map, move event handler registration to onStart, disable awareness built-in _checkInterval, resend sync step 1 after wake, simplify send/error handling, and allow onLoad to return a seeded YDoc. - Provider: switch awareness listener from "update" to "change", disable client _checkInterval and provider liveness timer, clear stale awareness meta on WS close, bump awareness clock on reconnect, and fix trailing-slash stripping bug. - Fixture: await super.onStart() in MonacoServer.onStart to ensure proper async startup. These changes enable connections and awareness to survive Durable Object hibernation and reduce unnecessary heartbeat traffic.
🦋 Changeset detectedLatest commit: f9fead4 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
hono-party
partyfn
partyserver
partysocket
partysub
partysync
partytracks
partywhen
y-partyserver
commit: |
Collaborator
Author
|
lol thanks @MrgSub. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds full Durable Object hibernation support to
y-partyserver. Previously, the server tracked connections in an in-memoryMap(WSSharedDoc.conns) which was lost on hibernation, breaking Yjs sync and awareness propagation after wake-up. This PR replaces that with hibernation-compatible primitives and suppresses awareness heartbeats that were preventing DOs from hibernating in the first place.Highlight: Hibernation Support
With
hibernate: true, Durable Objects can now actually hibernate during idle sessions. Previously, the awareness protocol's built-in 15-second heartbeat kept generating WebSocket traffic, preventing hibernation indefinitely. This PR suppresses those heartbeats on both client and server, and ensures the server recovers its document state from connected clients after waking up.Server changes (
packages/y-partyserver/src/server/index.ts)Connection tracking survives hibernation
WSSharedDoc.conns(Map<Connection, Set<number>>) — lost on hibernationconnection.setState()withAWARENESS_IDS_KEYto persist awareness client IDs per connection via WebSocket attachments (survives hibernation)getAwarenessIds()/setAwarenessIds()helpers with defensive try/catchEvent handlers moved to
onStart()WSSharedDocconstructor intoonStart(), where they usethis.getConnections()instead of the removedconnsMapHibernation wake-up re-sync
onStart()registers handlers, it sends sync step 1 to all existing connectionsTimer cleanup
awareness._checkIntervalcleared inWSSharedDocconstructor to prevent the protocol's internal timer from defeating hibernationCleanup
closeConn()helper — awareness cleanup now happens inonClosevia persisted connection statesend()— silently returns on broken connections instead of forcibly closing thembroadcastCustomMessageusesfor...ofovergetConnections()instead ofconns.forEachonLoad()return type toPromise<YDoc | void>Provider changes (
packages/y-partyserver/src/provider/index.ts)Awareness heartbeat suppression
awareness.on("update")toawareness.on("change")— clock-only renewals (the 15s heartbeat) no longer produce network trafficawareness._checkIntervalon the client — stops clock renewals and peer timeout removal_checkIntervalliveness timer (was coupled to the heartbeat)Reconnection fixes
metafor remote clients on WebSocket close — ensures reconnecting clients' awareness updates are accepted (clock check starts fresh)setLocalState(getLocalState())on reconnect — belt-and-suspenders with the meta cleanupBug fix
host.slice(0, -1)result was not assigned back tohost, so trailing slashes were never actually strippedTest coverage
23 unit tests — including:
_checkIntervalis disabled)16 integration tests — all existing tests pass unchanged
14 hibernation tests (3 new) — using
server.restart()pattern:onStartCountincrements on each restart (storage-backed tracker)New test infrastructure
YHibernateTrackerDO — tracksonStartcall count in storage, exposes it via HTTPintegration-wrangler.jsoncbindings and migrations