Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ wsOpts = {
awareness: new awarenessProtocol.Awareness(ydoc),
// Specify the maximum amount to wait between reconnects (we use exponential backoff).
maxBackoffTime: 2500
// Specify the maximum amount to wait between reconnects if previous connection succeeded (we use exponential backoff).
// This prevents connections that close right after their successful creation from being retried immediately.
// Backoff only resets when a connection has been open for `maxBackoffIntervalOnSuccessfulConnects * 2` ms
maxBackoffIntervalOnSuccessfulConnects: 2500
}
```

Expand Down
17 changes: 17 additions & 0 deletions src/y-websocket.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,16 @@ const closeWebsocketConnection = (provider, ws, event) => {
* @param {WebsocketProvider} provider
*/
const setupWS = (provider) => {
// Start with 100ms interval between successful connects and increase with exponential backoff
const backoff = math.min(math.pow(2, provider.wsSubsequentConnects) * 50, provider.maxBackoffIntervalOnSuccessfulConnects)
const timeout = provider.wsLastConnectAt ? Date.now() - provider.wsLastConnectAt.getTime() : backoff
if (timeout < backoff) {
setTimeout(setupWS, backoff - timeout, provider)
return
} else if (timeout > provider.maxBackoffIntervalOnSuccessfulConnects * 2) {
provider.wsSubsequentConnects = 0
}

if (provider.shouldConnect && provider.ws === null) {
const websocket = new provider._WS(provider.url, provider.protocols)
websocket.binaryType = 'arraybuffer'
Expand All @@ -194,6 +204,8 @@ const setupWS = (provider) => {
closeWebsocketConnection(provider, websocket, event)
}
websocket.onopen = () => {
provider.wsLastConnectAt = new Date()
provider.wsSubsequentConnects++
provider.wsLastMessageReceived = time.getUnixTime()
provider.wsconnecting = false
provider.wsconnected = true
Expand Down Expand Up @@ -265,6 +277,7 @@ export class WebsocketProvider extends ObservableV2 {
* @param {typeof WebSocket} [opts.WebSocketPolyfill] Optionall provide a WebSocket polyfill
* @param {number} [opts.resyncInterval] Request server state every `resyncInterval` milliseconds
* @param {number} [opts.maxBackoffTime] Maximum amount of time to wait before trying to reconnect (we try to reconnect using exponential backoff)
* @param {number} [opts.maxBackoffIntervalOnSuccessfulConnects] Maximum amount of time to wait before trying to reconnect if previous connection succeeded (we try to reconnect using exponential backoff). Backoff only resets after a connection has been open for `maxBackoffIntervalOnSuccessfulConnects * 2` ms
* @param {boolean} [opts.disableBc] Disable cross-tab BroadcastChannel communication
*/
constructor (serverUrl, roomname, doc, {
Expand All @@ -275,6 +288,7 @@ export class WebsocketProvider extends ObservableV2 {
WebSocketPolyfill = WebSocket,
resyncInterval = -1,
maxBackoffTime = 2500,
maxBackoffIntervalOnSuccessfulConnects = 2500,
disableBc = false
} = {}) {
super()
Expand All @@ -285,6 +299,7 @@ export class WebsocketProvider extends ObservableV2 {
this.serverUrl = serverUrl
this.bcChannel = serverUrl + '/' + roomname
this.maxBackoffTime = maxBackoffTime
this.maxBackoffIntervalOnSuccessfulConnects = maxBackoffIntervalOnSuccessfulConnects
/**
* The specified url parameters. This can be safely updated. The changed parameters will be used
* when a new connection is established.
Expand All @@ -301,6 +316,8 @@ export class WebsocketProvider extends ObservableV2 {
this.bcconnected = false
this.disableBc = disableBc
this.wsUnsuccessfulReconnects = 0
this.wsLastConnectAt = null
this.wsSubsequentConnects = 0
this.messageHandlers = messageHandlers.slice()
/**
* @type {boolean}
Expand Down