You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Timestamp when the current interval window ends. Kept accurate at every window transition: `#initializeIntervalIfNeeded` sets it when a window starts and `#onInterval` advances it as the recurring timer rolls into each new window. This is the source of truth for whether a task added after the queue goes idle belongs to a fresh window, so it must not go stale.
32
+
*/
30
33
#intervalEnd =0;
31
34
32
-
#lastExecutionTime =0;
33
-
35
+
// Recurring timer that drives windows while the queue is actively processing. Absent (`undefined`) once the queue goes idle.
34
36
#intervalId?: NodeJS.Timeout;
35
37
38
+
// One-shot timer used while idle to resume at the next window boundary, since `#intervalId` is cleared when idle.
// Fixed window mode. While the recurring timer runs it already governs the windows, so pausing is only decided here when the queue is idle (the timer is absent) and we rely on `#intervalEnd`.
238
241
if(this.#intervalId ===undefined){
239
242
constdelay=this.#intervalEnd -now;
240
243
if(delay<0){
241
-
// If the interval has expired while idle, check if we should enforce the interval
242
-
// from the last task execution. This ensures proper spacing between tasks even
243
-
// when the queue becomes empty and then new tasks are added.
// Only touch the recurring interval timer here. When resumed via a timeout instead, `#intervalId` is undefined and `#initializeIntervalIfNeeded` sets `#intervalEnd` right after.
355
+
if(this.#intervalId !==undefined){
356
+
if(this.#intervalCount ===0&&this.#pending ===0){
357
+
this.#clearIntervalTimer();
358
+
}else{
359
+
// The recurring timer fired, starting a new window. Keep the boundary accurate so tasks added after the queue later goes idle are scheduled against the correct window.
// Fill both slots spread across the window, after which the queue goes idle.
1074
+
queue.add(()=>undefined);
1075
+
awaitdelay(120);
1076
+
queue.add(()=>undefined);
1077
+
awaitqueue.onIdle();
1078
+
1079
+
// Added while still inside the window [0, 200): the cap is reached, so it must wait for the boundary, not run immediately. This guards against the reset firing before the window has actually expired.
1080
+
conststart=Date.now();
1081
+
awaitqueue.add(()=>undefined);
1082
+
constwaited=Date.now()-start;
1083
+
1084
+
assert.ok(waited>=40,`Task should wait for the current window to end, but only waited ${waited}ms`);
1085
+
assert.ok(Date.now()-windowStart>=190,'Task should run at the window boundary');
1086
+
});
1087
+
1002
1088
test('interval maintained when queue becomes empty multiple times',async()=>{
0 commit comments