Skip to content

Commit 4dde565

Browse files
committed
chore: extract random timeout
1 parent d3a1ac7 commit 4dde565

File tree

2 files changed

+57
-14
lines changed

2 files changed

+57
-14
lines changed
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/**
2+
* Enables waiting a random time before doing an action (using `setTimeout`),
3+
* with possibility to apply a multipliers to manipulate said time.
4+
*/
5+
export class RandomTimeout {
6+
private timeout: ReturnType<typeof setTimeout> | undefined;
7+
8+
public constructor(
9+
/**
10+
* The maximum interval one would wait before the call is made, in milliseconds.
11+
*/
12+
private maxIntervalMs: number,
13+
/**
14+
* When not zero: Anytime a call is made, then a new call will be rescheduled
15+
* using this multiplier
16+
*/
17+
private multiplierOnCall: number,
18+
/**
19+
* The function to call when the timer is reached
20+
*/
21+
private callback: () => void | Promise<void>
22+
) {}
23+
24+
/**
25+
* Use to start the timer. If a timer was already set, it deletes it and
26+
* schedule a new one.
27+
* @param multiplier applied to [[maxIntervalMs]]
28+
*/
29+
public restart(multiplier: number = 1): void {
30+
this.stop();
31+
32+
if (this.maxIntervalMs) {
33+
const timeoutMs = Math.random() * this.maxIntervalMs * multiplier;
34+
35+
this.timeout = setTimeout(() => {
36+
void this.callback();
37+
void this.restart(this.multiplierOnCall);
38+
}, timeoutMs);
39+
}
40+
}
41+
42+
public stop(): void {
43+
if (this.timeout) {
44+
clearTimeout(this.timeout);
45+
}
46+
}
47+
}

packages/sdk/src/reliable_channel/reliable_channel.ts

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import {
3535

3636
import { ReliableChannelEvent, ReliableChannelEvents } from "./events.js";
3737
import { MissingMessageRetriever } from "./missing_message_retriever.js";
38+
import { RandomTimeout } from "./random_timeout.js";
3839
import { RetryManager } from "./retry_manager.js";
3940
import { SyncStatus } from "./sync_status.js";
4041

@@ -151,8 +152,7 @@ export class ReliableChannel<
151152
) => AsyncGenerator<Promise<T | undefined>[]>;
152153

153154
private eventListenerCleanups: Array<() => void> = [];
154-
private readonly syncMinIntervalMs: number;
155-
private syncTimeout: ReturnType<typeof setTimeout> | undefined;
155+
private syncRandomTimeout: RandomTimeout;
156156
private sweepInBufInterval: ReturnType<typeof setInterval> | undefined;
157157
private readonly sweepInBufIntervalMs: number;
158158
private processTaskTimeout: ReturnType<typeof setTimeout> | undefined;
@@ -207,8 +207,11 @@ export class ReliableChannel<
207207
}
208208
}
209209

210-
this.syncMinIntervalMs =
211-
options?.syncMinIntervalMs ?? DEFAULT_SYNC_MIN_INTERVAL_MS;
210+
this.syncRandomTimeout = new RandomTimeout(
211+
options?.syncMinIntervalMs ?? DEFAULT_SYNC_MIN_INTERVAL_MS,
212+
2,
213+
this.sendSyncMessage.bind(this)
214+
);
212215

213216
this.sweepInBufIntervalMs =
214217
options?.sweepInBufIntervalMs ?? DEFAULT_SWEEP_IN_BUF_INTERVAL_MS;
@@ -244,7 +247,7 @@ export class ReliableChannel<
244247

245248
/**
246249
* Emit events when the channel is aware of missing message.
247-
* Note that "syncd" may mean some messages are irretrievably lost.
250+
* Note that "synced" may mean some messages are irretrievably lost.
248251
* Check the emitted data for details.
249252
*
250253
* @emits [[StatusEvents]]
@@ -592,18 +595,11 @@ export class ReliableChannel<
592595
void this.restartSync(2);
593596
}, timeoutMs);
594597
}
598+
this.syncRandomTimeout.restart(multiplier);
595599
}
596600

597601
private stopSync(): void {
598-
if (this.syncTimeout) {
599-
clearTimeout(this.syncTimeout);
600-
this.syncTimeout = undefined;
601-
}
602-
}
603-
604-
// Used to enable overriding when testing
605-
private random(): number {
606-
return Math.random();
602+
this.syncRandomTimeout.stop();
607603
}
608604

609605
private safeSendEvent<T extends ReliableChannelEvent>(

0 commit comments

Comments
 (0)