Skip to content

Commit a6323d8

Browse files
committed
chore: extract random timeout
1 parent 5e3a7ce commit a6323d8

File tree

2 files changed

+57
-26
lines changed

2 files changed

+57
-26
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 & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import {
3434

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

@@ -150,8 +151,7 @@ export class ReliableChannel<
150151
options?: Partial<QueryRequestParams>
151152
) => AsyncGenerator<Promise<T | undefined>[]>;
152153

153-
private readonly syncMinIntervalMs: number;
154-
private syncTimeout: ReturnType<typeof setTimeout> | undefined;
154+
private syncRandomTimeout: RandomTimeout;
155155
private sweepInBufInterval: ReturnType<typeof setInterval> | undefined;
156156
private readonly sweepInBufIntervalMs: number;
157157
private processTaskTimeout: ReturnType<typeof setTimeout> | undefined;
@@ -205,8 +205,11 @@ export class ReliableChannel<
205205
}
206206
}
207207

208-
this.syncMinIntervalMs =
209-
options?.syncMinIntervalMs ?? DEFAULT_SYNC_MIN_INTERVAL_MS;
208+
this.syncRandomTimeout = new RandomTimeout(
209+
options?.syncMinIntervalMs ?? DEFAULT_SYNC_MIN_INTERVAL_MS,
210+
2,
211+
this.sendSyncMessage.bind(this)
212+
);
210213

211214
this.sweepInBufIntervalMs =
212215
options?.sweepInBufIntervalMs ?? DEFAULT_SWEEP_IN_BUF_INTERVAL_MS;
@@ -242,7 +245,7 @@ export class ReliableChannel<
242245

243246
/**
244247
* Emit events when the channel is aware of missing message.
245-
* Note that "syncd" may mean some messages are irretrievably lost.
248+
* Note that "synced" may mean some messages are irretrievably lost.
246249
* Check the emitted data for details.
247250
*
248251
* @emits [[StatusEvents]]
@@ -547,30 +550,11 @@ export class ReliableChannel<
547550
}
548551

549552
private restartSync(multiplier: number = 1): void {
550-
if (this.syncTimeout) {
551-
clearTimeout(this.syncTimeout);
552-
}
553-
if (this.syncMinIntervalMs) {
554-
const timeoutMs = this.random() * this.syncMinIntervalMs * multiplier;
555-
556-
this.syncTimeout = setTimeout(() => {
557-
void this.sendSyncMessage();
558-
// Always restart a sync, no matter whether the message was sent.
559-
// Set a multiplier so we wait a bit longer to not hog the conversation
560-
void this.restartSync(2);
561-
}, timeoutMs);
562-
}
553+
this.syncRandomTimeout.restart(multiplier);
563554
}
564555

565556
private stopSync(): void {
566-
if (this.syncTimeout) {
567-
clearTimeout(this.syncTimeout);
568-
}
569-
}
570-
571-
// Used to enable overriding when testing
572-
private random(): number {
573-
return Math.random();
557+
this.syncRandomTimeout.stop();
574558
}
575559

576560
private safeSendEvent<T extends ReliableChannelEvent>(

0 commit comments

Comments
 (0)