diff --git a/.changeset/late-mice-explode.md b/.changeset/late-mice-explode.md new file mode 100644 index 0000000000..b081524347 --- /dev/null +++ b/.changeset/late-mice-explode.md @@ -0,0 +1,5 @@ +--- +'livekit-client': patch +--- + +Improve reconnect timeout handling diff --git a/.changeset/smart-lemons-appear.md b/.changeset/smart-lemons-appear.md new file mode 100644 index 0000000000..559d1db0af --- /dev/null +++ b/.changeset/smart-lemons-appear.md @@ -0,0 +1,5 @@ +--- +'livekit-client': patch +--- + +Customizable reconnect policy diff --git a/src/room/DefaultReconnectPolicy.ts b/src/room/DefaultReconnectPolicy.ts index 27edea4e5e..e72703f573 100644 --- a/src/room/DefaultReconnectPolicy.ts +++ b/src/room/DefaultReconnectPolicy.ts @@ -1,16 +1,18 @@ import { ReconnectContext, ReconnectPolicy } from './ReconnectPolicy'; +const maxRetryDelay = 7000; + const DEFAULT_RETRY_DELAYS_IN_MS = [ 0, 300, 2 * 2 * 300, 3 * 3 * 300, 4 * 4 * 300, - 5 * 5 * 300, - 6 * 6 * 300, - 7 * 7 * 300, - 8 * 8 * 300, - 9 * 9 * 300, + maxRetryDelay, + maxRetryDelay, + maxRetryDelay, + maxRetryDelay, + maxRetryDelay, ]; class DefaultReconnectPolicy implements ReconnectPolicy { @@ -21,7 +23,7 @@ class DefaultReconnectPolicy implements ReconnectPolicy { } public nextRetryDelayInMs(context: ReconnectContext): number | null { - if (context.retryCount === this._retryDelays.length) return null; + if (context.retryCount >= this._retryDelays.length) return null; const retryDelay = this._retryDelays[context.retryCount]; if (context.retryCount <= 1) return retryDelay; diff --git a/src/room/RTCEngine.ts b/src/room/RTCEngine.ts index bec35ac649..3d75b478d7 100644 --- a/src/room/RTCEngine.ts +++ b/src/room/RTCEngine.ts @@ -2,6 +2,7 @@ import { EventEmitter } from 'events'; import type TypedEventEmitter from 'typed-emitter'; import { SignalClient, SignalOptions } from '../api/SignalClient'; import log from '../logger'; +import { RoomOptions } from '../options'; import { ClientConfigSetting, ClientConfiguration, @@ -19,13 +20,12 @@ import { SignalTarget, TrackPublishedResponse, } from '../proto/livekit_rtc'; +import DefaultReconnectPolicy from './DefaultReconnectPolicy'; import { ConnectionError, TrackInvalidError, UnexpectedConnectionState } from './errors'; import { EngineEvent } from './events'; import PCTransport from './PCTransport'; -import { isFireFox, isWeb, sleep } from './utils'; -import { RoomOptions } from '../options'; import { ReconnectContext, ReconnectPolicy } from './ReconnectPolicy'; -import DefaultReconnectPolicy from './DefaultReconnectPolicy'; +import { isFireFox, isWeb, sleep } from './utils'; const lossyDataChannel = '_lossy'; const reliableDataChannel = '_reliable'; @@ -99,6 +99,8 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit private reconnectPolicy: ReconnectPolicy; + private reconnectTimeout?: ReturnType; + constructor(private options: RoomOptions) { super(); this.client = new SignalClient(); @@ -474,7 +476,10 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit log.debug(`reconnecting in ${delay}ms`); - setTimeout(async () => { + if (this.reconnectTimeout) { + clearTimeout(this.reconnectTimeout); + } + this.reconnectTimeout = setTimeout(async () => { if (this._isClosed) { return; } @@ -501,6 +506,9 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit } this.reconnectAttempts = 0; this.fullReconnectOnNext = false; + if (this.reconnectTimeout) { + clearTimeout(this.reconnectTimeout); + } } catch (e) { this.reconnectAttempts += 1; let reconnectRequired = false; @@ -597,7 +605,11 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit try { await this.client.reconnect(this.url, this.token); } catch (e) { - throw new SignalReconnectError(e); + let message = ''; + if (e instanceof Error) { + message = e.message; + } + throw new SignalReconnectError(message); } this.emit(EngineEvent.SignalResumed);