Skip to content

Commit

Permalink
Ensure new provider works with older server versions (#363)
Browse files Browse the repository at this point in the history
The new client relies on a message type in order to support heartbeats
and sync status. If it's talking to an older server version, the server
will ignore its requests for heartbeats, and the client will assume the
connection is unhealthy and attempt to reconnect in a periodic loop.

To test this, run the examples along with an old version of the server,
e.g. `npx [email protected] serve`

This fixes the library by adding a boolean field
`receivedAtLeastOneSyncResponse`. As long as this is `false`, we will
continue to send heartbeats and sync status requests, but we will never
terminate a connection over a missed heartbeat.

This is a somewhat crude approach. We should support version negotiation
eventually. But it's nice and simple, and will be easy to rip out later.
  • Loading branch information
paulgb authored Dec 18, 2024
1 parent 8391985 commit 87f4224
Showing 1 changed file with 22 additions and 0 deletions.
22 changes: 22 additions & 0 deletions js-pkg/client/src/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,17 @@ export class YSweetProvider {

private retries: number = 0

/**
* Older versions of the Y-Sweet server did not support the sync message, and would ignore it.
* This may lead to the client thinking the server is offline, when really it just doesn't
* know how to return a heartbeat.
*
* Eventually, we will build protocol version negotiation into the handshake. Until then, we
* use a simple approach: until we receive the first sync message back, we assume the server
* is an older version for the purpose of the heartbeat logic.
*/
private receivedAtLeastOneSyncResponse: boolean = false

constructor(
private authEndpoint: AuthEndpoint,
private docId: string,
Expand Down Expand Up @@ -226,6 +237,13 @@ export class YSweetProvider {
if (this.connectionTimeoutHandle) {
return
}

if (!this.receivedAtLeastOneSyncResponse) {
// Until we receive the first sync response on the connection, we assume
// the server is an older version.
return
}

this.connectionTimeoutHandle = setTimeout(() => {
if (this.websocket) {
this.websocket.close()
Expand Down Expand Up @@ -265,6 +283,8 @@ export class YSweetProvider {
if (emit) {
this.emit(EVENT_LOCAL_CHANGES, false)
}

this.receivedAtLeastOneSyncResponse = true
}

private setStatus(status: YSweetStatus) {
Expand Down Expand Up @@ -482,6 +502,8 @@ export class YSweetProvider {
this.checkSync()
this.broadcastAwareness()
this.resetHeartbeat()

this.receivedAtLeastOneSyncResponse = false
}

private receiveMessage(event: MessageEvent) {
Expand Down

0 comments on commit 87f4224

Please sign in to comment.