WebSocket keepalive changes#648
Merged
Merged
Conversation
🦋 Changeset detectedLatest commit: 430f99f The changes in this PR will be included in the next version bump. This PR includes changesets to release 7 packages
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 |
360b135 to
a31ddb5
Compare
Chriztiaan
previously approved these changes
Jul 2, 2025
…ync-js into websocket-keepalives
rkistner
commented
Jul 2, 2025
stevensJourney
approved these changes
Jul 2, 2025
Collaborator
stevensJourney
left a comment
There was a problem hiding this comment.
The changes here look good to me. Happy from my side :)
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.
Background
RSocket handles keepalive as follows:
keepAlivems (20s).lifetimems (30s).That gives a 10s grace period between sending and receiving the message.
The issue here comes in when there is either:
Either of the above could block the keepalive response for more than that 10s, resulting in
Error: Closed. Original cause [Error: No keep-alive acks for 30000 millis]..One workaround was added in #494, reducing the number of messages that are requested by the client at a time. However, this can decrease throughput.
Keepalive Changes
This implements an additional workaround that:
lifetimeto 90s.This applies per-message, not per-byte or per-frame. This means we can still get a timeout error if a single message takes more than 10s to send over the connection. Our messages are generally limited to 1MB in size (unless a single operation is larger than that), so it should cover most cases.
BSON parsing changes
This now delays parsing of BSON data until the line is processed, rather than when it is received. This helps since:
The Rust implementation takes this further to move the BSON parsing into the SQLite extension, which helps even more.
This refactors the DataStream handling a bit to support this. This also fixes some type issues we had, such as mixing up Uint8Array and ArrayBuffer.
Future options
Testing
NodeJS
Did regression testing on NodeJS using all 4 combinations of
connectionMethodandclientImplementation- no issues found.React Native
On React-Native, tested using websockets only, for both
clientImplementationmethods.For the JavaScript implementation, overall sync performance appears to be slightly better now, but I didn't do proper benchmarking.Before, data would typically be processed batches of 10x deserialize, then 10x saveSyncData, alternating between them. Now, one message is deserialized at a time.
For op-sqlite, I used react-native-barebones-opsqlite. I had trouble with the fetch implementation - both write checkpoints and http streams get
Value is undefined, expected a String(see facebook/react-native#27741 (comment)). But websockets do work with both the JS and Rust implementations.Web
Tested using the diagnostics app, using all 4 combinations of
connectionMethodandclientImplementation- no issues found.TODO