dynamic-throttled-queue 2.3.0-rc.e78fc2f → 3.0.0-rc.ea3019c
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +298 -156
- package/dist/adaptive-rate.d.ts +56 -21
- package/dist/adaptive-rate.js +123 -22
- package/dist/adaptive-rate.js.map +1 -1
- package/dist/dynamic-throttled-queue.d.ts +9 -67
- package/dist/dynamic-throttled-queue.js +23 -50
- package/dist/dynamic-throttled-queue.js.map +1 -1
- package/dist/pending-work.d.ts +2 -0
- package/dist/pending-work.js +31 -13
- package/dist/pending-work.js.map +1 -1
- package/dist/retry-policy.d.ts +25 -0
- package/dist/retry-policy.js +73 -0
- package/dist/retry-policy.js.map +1 -0
- package/dist/scheduler.d.ts +61 -2
- package/dist/scheduler.js +164 -76
- package/dist/scheduler.js.map +1 -1
- package/package.json +14 -10
- package/skills/configure-throttled-queue/SKILL.md +340 -0
- package/skills/configure-throttled-queue/references/lifecycle.md +46 -0
- package/skills/configure-throttled-queue/references/rate-strategies.md +68 -0
- package/skills/configure-throttled-queue/references/retries.md +52 -0
- package/skills/configure-throttled-queue/references/state-and-idle.md +38 -0
- package/dist/retry-backoff.d.ts +0 -2
- package/dist/retry-backoff.js +0 -31
- package/dist/retry-backoff.js.map +0 -1
package/dist/adaptive-rate.d.ts
CHANGED
|
@@ -1,17 +1,44 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
export type RateStrategyObservation = Readonly<{
|
|
2
|
+
currentRate: number;
|
|
3
|
+
minRate: number;
|
|
4
|
+
maxRate: number;
|
|
5
|
+
errorCount: number;
|
|
6
|
+
errorThreshold: number;
|
|
7
|
+
hasPendingWork: boolean;
|
|
8
|
+
wasBackedOff: boolean;
|
|
9
|
+
}>;
|
|
10
|
+
export type RateStrategyDecision = Readonly<{
|
|
11
|
+
nextRate: number;
|
|
12
|
+
shouldBackOff: boolean;
|
|
13
|
+
}>;
|
|
14
|
+
export type RateStrategy = (observation: RateStrategyObservation) => RateStrategyDecision;
|
|
15
|
+
export type AimdOptions = {
|
|
16
|
+
increaseBy?: number;
|
|
17
|
+
decreaseFactor?: number;
|
|
18
|
+
};
|
|
19
|
+
export type FailureOutcome = Readonly<{
|
|
20
|
+
kind: "returned-false";
|
|
21
|
+
}> | Readonly<{
|
|
22
|
+
kind: "thrown";
|
|
23
|
+
error: unknown;
|
|
24
|
+
}> | Readonly<{
|
|
25
|
+
kind: "rejected";
|
|
26
|
+
error: unknown;
|
|
27
|
+
}>;
|
|
28
|
+
export type RateOutcomeClassifier = (outcome: FailureOutcome) => boolean;
|
|
29
|
+
export type AdjustmentTiming = "interval" | "settled";
|
|
30
|
+
export declare const linear: RateStrategy;
|
|
31
|
+
export declare function aimd({ increaseBy, decreaseFactor }?: AimdOptions): RateStrategy;
|
|
7
32
|
/** Reports how one started callback settled: `undefined` for success, otherwise the failure. */
|
|
8
|
-
export type SettlementReporter = (outcome:
|
|
33
|
+
export type SettlementReporter = (outcome: FailureOutcome | undefined) => void;
|
|
9
34
|
export type AdaptiveRateOptions = {
|
|
10
|
-
|
|
11
|
-
|
|
35
|
+
minRate: number;
|
|
36
|
+
maxRate: number;
|
|
12
37
|
interval: number;
|
|
13
|
-
|
|
14
|
-
|
|
38
|
+
/** Makes one start due every `interval / rate` ms instead of `rate` starts once per interval. */
|
|
39
|
+
evenlySpaced: boolean;
|
|
40
|
+
errorThreshold: number;
|
|
41
|
+
backOff: boolean;
|
|
15
42
|
adjustmentTiming: AdjustmentTiming;
|
|
16
43
|
rateStrategy: RateStrategy;
|
|
17
44
|
rateOutcomeClassifier?: RateOutcomeClassifier;
|
|
@@ -20,12 +47,12 @@ export type AdaptiveRateOptions = {
|
|
|
20
47
|
export type AdaptiveRateHost = {
|
|
21
48
|
/** Whether accepted work is waiting to start. */
|
|
22
49
|
hasPendingWork: () => boolean;
|
|
23
|
-
/**
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
50
|
+
/**
|
|
51
|
+
* Starts are due: start up to `limit` queued callbacks as concurrency allows, calling `started()` for each.
|
|
52
|
+
* Returns whether a slot is still free. When none is, no further start becomes due until `start()`
|
|
53
|
+
* reports a freed slot.
|
|
54
|
+
*/
|
|
55
|
+
startsDue: (limit: number) => boolean;
|
|
29
56
|
/** The rate strategy failed; the host must call `stop()`. The error is rethrown after this returns. */
|
|
30
57
|
failed: (error: unknown) => void;
|
|
31
58
|
};
|
|
@@ -33,15 +60,23 @@ export type AdaptiveRate = {
|
|
|
33
60
|
readonly rate: number;
|
|
34
61
|
readonly rateIncreases: number;
|
|
35
62
|
readonly rateDecreases: number;
|
|
36
|
-
|
|
37
|
-
|
|
63
|
+
/**
|
|
64
|
+
* Ends a pause, then begins observing if idle and work is pending. While starts are open and no start
|
|
65
|
+
* is scheduled (concurrency was full), makes starts due now once a spacing has passed since the last
|
|
66
|
+
* start, or schedules them for when it has. During `startsDue`, the batch's own follow-up covers it.
|
|
67
|
+
*/
|
|
38
68
|
start: () => void;
|
|
39
|
-
/** Reports that every queued callback has started. */
|
|
40
|
-
drained: () => void;
|
|
41
69
|
/** Ends observation. Settled timing discards its in-progress window. */
|
|
42
70
|
stop: () => void;
|
|
43
71
|
/** Stops and discards the observation. Settlements are ignored until `start()` or `stop()`. */
|
|
44
72
|
pause: () => void;
|
|
73
|
+
/**
|
|
74
|
+
* Makes no start due and no rate decision until `start()`, while settlements keep counting toward the
|
|
75
|
+
* next decision. Settled timing closes its collection interval early and decides that window once
|
|
76
|
+
* `start()` is called and every callback started in it has settled; interval timing begins a fresh
|
|
77
|
+
* interval on `start()`.
|
|
78
|
+
*/
|
|
79
|
+
suspend: () => void;
|
|
45
80
|
/** Reports a callback start. Call the returned reporter once when that callback settles. */
|
|
46
81
|
started: () => SettlementReporter;
|
|
47
82
|
};
|
package/dist/adaptive-rate.js
CHANGED
|
@@ -1,3 +1,29 @@
|
|
|
1
|
+
export const linear = ({ minRate, maxRate, currentRate, errorCount, errorThreshold, hasPendingWork, wasBackedOff, }) => {
|
|
2
|
+
if (errorCount >= errorThreshold) {
|
|
3
|
+
return { nextRate: Math.max(minRate, currentRate - 1), shouldBackOff: true };
|
|
4
|
+
}
|
|
5
|
+
if (!wasBackedOff && errorCount === 0 && hasPendingWork) {
|
|
6
|
+
return { nextRate: Math.min(maxRate, currentRate + 1), shouldBackOff: false };
|
|
7
|
+
}
|
|
8
|
+
return { nextRate: currentRate, shouldBackOff: false };
|
|
9
|
+
};
|
|
10
|
+
export function aimd({ increaseBy = 1, decreaseFactor = 0.5 } = {}) {
|
|
11
|
+
if (!Number.isInteger(increaseBy) || increaseBy < 1) {
|
|
12
|
+
throw new Error("increaseBy must be a positive integer");
|
|
13
|
+
}
|
|
14
|
+
if (!Number.isFinite(decreaseFactor) || decreaseFactor <= 0 || decreaseFactor >= 1) {
|
|
15
|
+
throw new Error("decreaseFactor must be a number greater than 0 and less than 1");
|
|
16
|
+
}
|
|
17
|
+
return ({ currentRate, errorCount, errorThreshold, hasPendingWork, wasBackedOff }) => {
|
|
18
|
+
if (errorCount >= errorThreshold) {
|
|
19
|
+
return { nextRate: Math.floor(currentRate * decreaseFactor), shouldBackOff: true };
|
|
20
|
+
}
|
|
21
|
+
if (!wasBackedOff && errorCount === 0 && hasPendingWork) {
|
|
22
|
+
return { nextRate: currentRate + increaseBy, shouldBackOff: false };
|
|
23
|
+
}
|
|
24
|
+
return { nextRate: currentRate, shouldBackOff: false };
|
|
25
|
+
};
|
|
26
|
+
}
|
|
1
27
|
const ignoreSettlement = () => { };
|
|
2
28
|
function validateDecision(decision) {
|
|
3
29
|
if (typeof decision !== "object" || decision === null) {
|
|
@@ -42,6 +68,7 @@ function intervalTiming(context) {
|
|
|
42
68
|
started: () => context.record,
|
|
43
69
|
drained: stop,
|
|
44
70
|
stop,
|
|
71
|
+
suspend: stop,
|
|
45
72
|
};
|
|
46
73
|
}
|
|
47
74
|
/** Decides once every callback that started during one collection interval has settled. */
|
|
@@ -51,6 +78,10 @@ function settledTiming(context) {
|
|
|
51
78
|
let collecting = false;
|
|
52
79
|
let starts = 0;
|
|
53
80
|
let outstanding = 0;
|
|
81
|
+
/** Collection has ended and the window's decision waits for its outstanding starts to settle. */
|
|
82
|
+
let closed = false;
|
|
83
|
+
/** Suspended: a closed window's decision waits for `start()` as well. */
|
|
84
|
+
let suspended = false;
|
|
54
85
|
function open() {
|
|
55
86
|
timer = undefined;
|
|
56
87
|
if (!context.hasPendingWork()) {
|
|
@@ -59,6 +90,7 @@ function settledTiming(context) {
|
|
|
59
90
|
}
|
|
60
91
|
window++;
|
|
61
92
|
collecting = true;
|
|
93
|
+
closed = false;
|
|
62
94
|
starts = 0;
|
|
63
95
|
outstanding = 0;
|
|
64
96
|
context.resume();
|
|
@@ -72,11 +104,13 @@ function settledTiming(context) {
|
|
|
72
104
|
return;
|
|
73
105
|
}
|
|
74
106
|
collecting = false;
|
|
107
|
+
closed = true;
|
|
75
108
|
context.hold();
|
|
76
109
|
if (outstanding === 0)
|
|
77
110
|
finish();
|
|
78
111
|
}
|
|
79
112
|
function finish() {
|
|
113
|
+
closed = false;
|
|
80
114
|
const current = window;
|
|
81
115
|
const hold = context.decide();
|
|
82
116
|
if (current !== window)
|
|
@@ -87,7 +121,16 @@ function settledTiming(context) {
|
|
|
87
121
|
open();
|
|
88
122
|
}
|
|
89
123
|
return {
|
|
90
|
-
start
|
|
124
|
+
start() {
|
|
125
|
+
suspended = false;
|
|
126
|
+
if (!closed) {
|
|
127
|
+
open();
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
context.hold();
|
|
131
|
+
if (outstanding === 0)
|
|
132
|
+
finish();
|
|
133
|
+
},
|
|
91
134
|
started() {
|
|
92
135
|
if (!collecting)
|
|
93
136
|
return ignoreSettlement;
|
|
@@ -99,7 +142,7 @@ function settledTiming(context) {
|
|
|
99
142
|
return;
|
|
100
143
|
context.record(outcome);
|
|
101
144
|
outstanding--;
|
|
102
|
-
if (!
|
|
145
|
+
if (closed && !suspended && outstanding === 0)
|
|
103
146
|
finish();
|
|
104
147
|
};
|
|
105
148
|
},
|
|
@@ -108,20 +151,36 @@ function settledTiming(context) {
|
|
|
108
151
|
clearTimeout(timer);
|
|
109
152
|
timer = undefined;
|
|
110
153
|
collecting = false;
|
|
154
|
+
closed = false;
|
|
155
|
+
suspended = false;
|
|
111
156
|
window++;
|
|
112
157
|
context.idle();
|
|
113
158
|
},
|
|
159
|
+
suspend() {
|
|
160
|
+
clearTimeout(timer);
|
|
161
|
+
timer = undefined;
|
|
162
|
+
if (collecting) {
|
|
163
|
+
collecting = false;
|
|
164
|
+
closed = starts > 0;
|
|
165
|
+
}
|
|
166
|
+
suspended = true;
|
|
167
|
+
context.idle();
|
|
168
|
+
},
|
|
114
169
|
};
|
|
115
170
|
}
|
|
116
171
|
export function createAdaptiveRate(options, host) {
|
|
117
|
-
const {
|
|
118
|
-
let rate = Math.ceil((
|
|
172
|
+
const { minRate, maxRate, interval, evenlySpaced, errorThreshold, backOff, rateStrategy, rateOutcomeClassifier, onRateChange, } = options;
|
|
173
|
+
let rate = Math.ceil((maxRate + minRate) / 2);
|
|
119
174
|
let rateIncreases = 0;
|
|
120
175
|
let rateDecreases = 0;
|
|
121
176
|
let errorCount = 0;
|
|
122
177
|
let wasBackedOff = false;
|
|
123
178
|
let ignoringSettlements = false;
|
|
124
179
|
let pacing = "idle";
|
|
180
|
+
let lastStart = 0;
|
|
181
|
+
let startTimer;
|
|
182
|
+
let dispatching = false;
|
|
183
|
+
let batchStarts = 0;
|
|
125
184
|
function isRateReducing(outcome) {
|
|
126
185
|
try {
|
|
127
186
|
return rateOutcomeClassifier?.(outcome) ?? true;
|
|
@@ -143,10 +202,10 @@ export function createAdaptiveRate(options, host) {
|
|
|
143
202
|
function decide() {
|
|
144
203
|
const observation = Object.freeze({
|
|
145
204
|
currentRate: rate,
|
|
146
|
-
minRate
|
|
147
|
-
maxRate
|
|
205
|
+
minRate,
|
|
206
|
+
maxRate,
|
|
148
207
|
errorCount,
|
|
149
|
-
errorThreshold
|
|
208
|
+
errorThreshold,
|
|
150
209
|
hasPendingWork: host.hasPendingWork(),
|
|
151
210
|
wasBackedOff,
|
|
152
211
|
});
|
|
@@ -158,14 +217,47 @@ export function createAdaptiveRate(options, host) {
|
|
|
158
217
|
host.failed(error);
|
|
159
218
|
throw error;
|
|
160
219
|
}
|
|
161
|
-
const hold =
|
|
220
|
+
const hold = backOff && decision.shouldBackOff;
|
|
162
221
|
errorCount = 0;
|
|
163
222
|
wasBackedOff = hold;
|
|
164
|
-
applyRate(Math.min(
|
|
223
|
+
applyRate(Math.min(maxRate, Math.max(minRate, decision.nextRate)));
|
|
165
224
|
return hold;
|
|
166
225
|
}
|
|
226
|
+
function spacing() {
|
|
227
|
+
return evenlySpaced ? interval / rate : interval;
|
|
228
|
+
}
|
|
229
|
+
function scheduleStart(delay) {
|
|
230
|
+
clearTimeout(startTimer);
|
|
231
|
+
startTimer = setTimeout(startDue, delay);
|
|
232
|
+
}
|
|
233
|
+
function cancelStart() {
|
|
234
|
+
clearTimeout(startTimer);
|
|
235
|
+
startTimer = undefined;
|
|
236
|
+
}
|
|
237
|
+
/** Makes a batch of starts due once one spacing has passed since the last start. */
|
|
238
|
+
function startDue() {
|
|
239
|
+
startTimer = undefined;
|
|
240
|
+
const wait = lastStart + spacing() - Date.now();
|
|
241
|
+
if (wait > 0) {
|
|
242
|
+
scheduleStart(wait);
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
dispatching = true;
|
|
246
|
+
batchStarts = 0;
|
|
247
|
+
let slotFree;
|
|
248
|
+
try {
|
|
249
|
+
slotFree = host.startsDue(evenlySpaced ? 1 : rate);
|
|
250
|
+
}
|
|
251
|
+
finally {
|
|
252
|
+
dispatching = false;
|
|
253
|
+
}
|
|
254
|
+
if (!host.hasPendingWork())
|
|
255
|
+
timing.drained();
|
|
256
|
+
if (pacing === "open" && slotFree)
|
|
257
|
+
scheduleStart(spacing());
|
|
258
|
+
}
|
|
167
259
|
const context = {
|
|
168
|
-
interval
|
|
260
|
+
interval,
|
|
169
261
|
get pacing() {
|
|
170
262
|
return pacing;
|
|
171
263
|
},
|
|
@@ -177,11 +269,15 @@ export function createAdaptiveRate(options, host) {
|
|
|
177
269
|
decide,
|
|
178
270
|
resume() {
|
|
179
271
|
pacing = "open";
|
|
180
|
-
|
|
272
|
+
lastStart = Date.now();
|
|
273
|
+
scheduleStart(spacing());
|
|
181
274
|
},
|
|
182
275
|
hold(deferBy) {
|
|
183
276
|
pacing = "held";
|
|
184
|
-
|
|
277
|
+
if (deferBy === undefined)
|
|
278
|
+
cancelStart();
|
|
279
|
+
else
|
|
280
|
+
scheduleStart(spacing() + deferBy);
|
|
185
281
|
},
|
|
186
282
|
reopen() {
|
|
187
283
|
pacing = "open";
|
|
@@ -189,7 +285,7 @@ export function createAdaptiveRate(options, host) {
|
|
|
189
285
|
idle() {
|
|
190
286
|
wasBackedOff = false;
|
|
191
287
|
pacing = "idle";
|
|
192
|
-
|
|
288
|
+
cancelStart();
|
|
193
289
|
},
|
|
194
290
|
};
|
|
195
291
|
const timing = options.adjustmentTiming === "settled" ? settledTiming(context) : intervalTiming(context);
|
|
@@ -203,17 +299,14 @@ export function createAdaptiveRate(options, host) {
|
|
|
203
299
|
get rateDecreases() {
|
|
204
300
|
return rateDecreases;
|
|
205
301
|
},
|
|
206
|
-
get pacing() {
|
|
207
|
-
return pacing;
|
|
208
|
-
},
|
|
209
302
|
start() {
|
|
210
303
|
ignoringSettlements = false;
|
|
211
|
-
if (
|
|
304
|
+
if (!host.hasPendingWork())
|
|
212
305
|
return;
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
306
|
+
if (pacing === "idle")
|
|
307
|
+
timing.start();
|
|
308
|
+
else if (pacing === "open" && startTimer === undefined && !dispatching)
|
|
309
|
+
startDue();
|
|
217
310
|
},
|
|
218
311
|
stop() {
|
|
219
312
|
ignoringSettlements = false;
|
|
@@ -224,7 +317,15 @@ export function createAdaptiveRate(options, host) {
|
|
|
224
317
|
errorCount = 0;
|
|
225
318
|
ignoringSettlements = true;
|
|
226
319
|
},
|
|
227
|
-
|
|
320
|
+
suspend() {
|
|
321
|
+
ignoringSettlements = false;
|
|
322
|
+
timing.suspend();
|
|
323
|
+
},
|
|
324
|
+
started() {
|
|
325
|
+
if (dispatching && batchStarts++ === 0)
|
|
326
|
+
lastStart = Date.now();
|
|
327
|
+
return timing.started();
|
|
328
|
+
},
|
|
228
329
|
};
|
|
229
330
|
}
|
|
230
331
|
//# sourceMappingURL=adaptive-rate.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adaptive-rate.js","sourceRoot":"","sources":["../src/adaptive-rate.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"adaptive-rate.js","sourceRoot":"","sources":["../src/adaptive-rate.ts"],"names":[],"mappings":"AA+BA,MAAM,CAAC,MAAM,MAAM,GAAiB,CAAC,EACnC,OAAO,EACP,OAAO,EACP,WAAW,EACX,UAAU,EACV,cAAc,EACd,cAAc,EACd,YAAY,GACb,EAAE,EAAE;IACH,IAAI,UAAU,IAAI,cAAc,EAAE,CAAC;QACjC,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,WAAW,GAAG,CAAC,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;IAC/E,CAAC;IACD,IAAI,CAAC,YAAY,IAAI,UAAU,KAAK,CAAC,IAAI,cAAc,EAAE,CAAC;QACxD,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,WAAW,GAAG,CAAC,CAAC,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC;IAChF,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC;AACzD,CAAC,CAAC;AAEF,MAAM,UAAU,IAAI,CAAC,EAAE,UAAU,GAAG,CAAC,EAAE,cAAc,GAAG,GAAG,KAAkB,EAAE;IAC7E,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;QACpD,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC3D,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,cAAc,IAAI,CAAC,IAAI,cAAc,IAAI,CAAC,EAAE,CAAC;QACnF,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;IACpF,CAAC;IACD,OAAO,CAAC,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,EAAE,cAAc,EAAE,YAAY,EAAE,EAAE,EAAE;QACnF,IAAI,UAAU,IAAI,cAAc,EAAE,CAAC;YACjC,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,cAAc,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;QACrF,CAAC;QACD,IAAI,CAAC,YAAY,IAAI,UAAU,KAAK,CAAC,IAAI,cAAc,EAAE,CAAC;YACxD,OAAO,EAAE,QAAQ,EAAE,WAAW,GAAG,UAAU,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC;QACtE,CAAC;QACD,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC;IACzD,CAAC,CAAC;AACJ,CAAC;AAuFD,MAAM,gBAAgB,GAAuB,GAAG,EAAE,GAAE,CAAC,CAAC;AAEtD,SAAS,gBAAgB,CAAC,QAAiB;IACzC,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtD,MAAM,IAAI,SAAS,CAAC,6CAA6C,CAAC,CAAC;IACrE,CAAC;IACD,MAAM,SAAS,GAAG,QAAgC,CAAC;IACnD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC;QAClF,MAAM,IAAI,SAAS,CAAC,qDAAqD,CAAC,CAAC;IAC7E,CAAC;IACD,IAAI,OAAO,SAAS,CAAC,aAAa,KAAK,SAAS,EAAE,CAAC;QACjD,MAAM,IAAI,SAAS,CAAC,mDAAmD,CAAC,CAAC;IAC3E,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,yGAAyG;AACzG,SAAS,cAAc,CAAC,OAAsB;IAC5C,IAAI,IAA+C,CAAC;IACpD,IAAI,GAAG,GAAG,CAAC,CAAC;IAEZ,SAAS,MAAM;QACb,IAAI,GAAG,SAAS,CAAC;QACjB,MAAM,OAAO,GAAG,GAAG,CAAC;QACpB,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;QAC9B,IAAI,OAAO,KAAK,GAAG;YAAE,OAAO;QAC5B,IAAI,IAAI;YAAE,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;aACpC,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM;YAAE,OAAO,CAAC,MAAM,EAAE,CAAC;QACrD,IAAI,GAAG,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC9C,CAAC;IAED,SAAS,IAAI;QACX,YAAY,CAAC,IAAI,CAAC,CAAC;QACnB,IAAI,GAAG,SAAS,CAAC;QACjB,GAAG,EAAE,CAAC;QACN,OAAO,CAAC,IAAI,EAAE,CAAC;IACjB,CAAC;IAED,OAAO;QACL,KAAK;YACH,OAAO,CAAC,MAAM,EAAE,CAAC;YACjB,IAAI,GAAG,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC9C,CAAC;QACD,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM;QAC7B,OAAO,EAAE,IAAI;QACb,IAAI;QACJ,OAAO,EAAE,IAAI;KACd,CAAC;AACJ,CAAC;AAED,2FAA2F;AAC3F,SAAS,aAAa,CAAC,OAAsB;IAC3C,IAAI,KAAgD,CAAC;IACrD,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,IAAI,UAAU,GAAG,KAAK,CAAC;IACvB,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,iGAAiG;IACjG,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,yEAAyE;IACzE,IAAI,SAAS,GAAG,KAAK,CAAC;IAEtB,SAAS,IAAI;QACX,KAAK,GAAG,SAAS,CAAC;QAClB,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC;YAC9B,OAAO,CAAC,IAAI,EAAE,CAAC;YACf,OAAO;QACT,CAAC;QACD,MAAM,EAAE,CAAC;QACT,UAAU,GAAG,IAAI,CAAC;QAClB,MAAM,GAAG,KAAK,CAAC;QACf,MAAM,GAAG,CAAC,CAAC;QACX,WAAW,GAAG,CAAC,CAAC;QAChB,OAAO,CAAC,MAAM,EAAE,CAAC;QACjB,KAAK,GAAG,UAAU,CAAC,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC9C,CAAC;IAED,SAAS,KAAK;QACZ,KAAK,GAAG,SAAS,CAAC;QAClB,qGAAqG;QACrG,IAAI,MAAM,KAAK,CAAC,EAAE,CAAC;YACjB,IAAI,EAAE,CAAC;YACP,OAAO;QACT,CAAC;QACD,UAAU,GAAG,KAAK,CAAC;QACnB,MAAM,GAAG,IAAI,CAAC;QACd,OAAO,CAAC,IAAI,EAAE,CAAC;QACf,IAAI,WAAW,KAAK,CAAC;YAAE,MAAM,EAAE,CAAC;IAClC,CAAC;IAED,SAAS,MAAM;QACb,MAAM,GAAG,KAAK,CAAC;QACf,MAAM,OAAO,GAAG,MAAM,CAAC;QACvB,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;QAC9B,IAAI,OAAO,KAAK,MAAM;YAAE,OAAO;QAC/B,IAAI,IAAI;YAAE,KAAK,GAAG,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;;YAChD,IAAI,EAAE,CAAC;IACd,CAAC;IAED,OAAO;QACL,KAAK;YACH,SAAS,GAAG,KAAK,CAAC;YAClB,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,IAAI,EAAE,CAAC;gBACP,OAAO;YACT,CAAC;YACD,OAAO,CAAC,IAAI,EAAE,CAAC;YACf,IAAI,WAAW,KAAK,CAAC;gBAAE,MAAM,EAAE,CAAC;QAClC,CAAC;QACD,OAAO;YACL,IAAI,CAAC,UAAU;gBAAE,OAAO,gBAAgB,CAAC;YACzC,MAAM,SAAS,GAAG,MAAM,CAAC;YACzB,MAAM,EAAE,CAAC;YACT,WAAW,EAAE,CAAC;YACd,OAAO,OAAO,CAAC,EAAE;gBACf,IAAI,SAAS,KAAK,MAAM;oBAAE,OAAO;gBACjC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;gBACxB,WAAW,EAAE,CAAC;gBACd,IAAI,MAAM,IAAI,CAAC,SAAS,IAAI,WAAW,KAAK,CAAC;oBAAE,MAAM,EAAE,CAAC;YAC1D,CAAC,CAAC;QACJ,CAAC;QACD,OAAO,KAAI,CAAC;QACZ,IAAI;YACF,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,KAAK,GAAG,SAAS,CAAC;YAClB,UAAU,GAAG,KAAK,CAAC;YACnB,MAAM,GAAG,KAAK,CAAC;YACf,SAAS,GAAG,KAAK,CAAC;YAClB,MAAM,EAAE,CAAC;YACT,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,CAAC;QACD,OAAO;YACL,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,KAAK,GAAG,SAAS,CAAC;YAClB,IAAI,UAAU,EAAE,CAAC;gBACf,UAAU,GAAG,KAAK,CAAC;gBACnB,MAAM,GAAG,MAAM,GAAG,CAAC,CAAC;YACtB,CAAC;YACD,SAAS,GAAG,IAAI,CAAC;YACjB,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,CAAC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,OAA4B,EAAE,IAAsB;IACrF,MAAM,EACJ,OAAO,EACP,OAAO,EACP,QAAQ,EACR,YAAY,EACZ,cAAc,EACd,OAAO,EACP,YAAY,EACZ,qBAAqB,EACrB,YAAY,GACb,GAAG,OAAO,CAAC;IACZ,IAAI,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9C,IAAI,aAAa,GAAG,CAAC,CAAC;IACtB,IAAI,aAAa,GAAG,CAAC,CAAC;IACtB,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,IAAI,YAAY,GAAG,KAAK,CAAC;IACzB,IAAI,mBAAmB,GAAG,KAAK,CAAC;IAChC,IAAI,MAAM,GAAW,MAAM,CAAC;IAC5B,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,UAAqD,CAAC;IAC1D,IAAI,WAAW,GAAG,KAAK,CAAC;IACxB,IAAI,WAAW,GAAG,CAAC,CAAC;IAEpB,SAAS,cAAc,CAAC,OAAuB;QAC7C,IAAI,CAAC;YACH,OAAO,qBAAqB,EAAE,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC;QAClD,CAAC;QACD,MAAM,CAAC;YACL,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,SAAS,SAAS,CAAC,IAAY;QAC7B,IAAI,IAAI,KAAK,IAAI;YAAE,OAAO;QAC1B,IAAI,IAAI,GAAG,IAAI;YAAE,aAAa,EAAE,CAAC;;YAC5B,aAAa,EAAE,CAAC;QACrB,IAAI,GAAG,IAAI,CAAC;QACZ,YAAY,EAAE,CAAC,IAAI,CAAC,CAAC;IACvB,CAAC;IAED,SAAS,MAAM;QACb,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC;YAChC,WAAW,EAAE,IAAI;YACjB,OAAO;YACP,OAAO;YACP,UAAU;YACV,cAAc;YACd,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE;YACrC,YAAY;SACb,CAAC,CAAC;QACH,IAAI,QAA8B,CAAC;QACnC,IAAI,CAAC;YACH,QAAQ,GAAG,gBAAgB,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC,CAAC;QACzD,CAAC;QACD,OAAO,KAAK,EAAE,CAAC;YACb,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACnB,MAAM,KAAK,CAAC;QACd,CAAC;QACD,MAAM,IAAI,GAAG,OAAO,IAAI,QAAQ,CAAC,aAAa,CAAC;QAC/C,UAAU,GAAG,CAAC,CAAC;QACf,YAAY,GAAG,IAAI,CAAC;QACpB,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QACnE,OAAO,IAAI,CAAC;IACd,CAAC;IAED,SAAS,OAAO;QACd,OAAO,YAAY,CAAC,CAAC,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC;IACnD,CAAC;IAED,SAAS,aAAa,CAAC,KAAa;QAClC,YAAY,CAAC,UAAU,CAAC,CAAC;QACzB,UAAU,GAAG,UAAU,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC3C,CAAC;IAED,SAAS,WAAW;QAClB,YAAY,CAAC,UAAU,CAAC,CAAC;QACzB,UAAU,GAAG,SAAS,CAAC;IACzB,CAAC;IAED,oFAAoF;IACpF,SAAS,QAAQ;QACf,UAAU,GAAG,SAAS,CAAC;QACvB,MAAM,IAAI,GAAG,SAAS,GAAG,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAChD,IAAI,IAAI,GAAG,CAAC,EAAE,CAAC;YACb,aAAa,CAAC,IAAI,CAAC,CAAC;YACpB,OAAO;QACT,CAAC;QACD,WAAW,GAAG,IAAI,CAAC;QACnB,WAAW,GAAG,CAAC,CAAC;QAChB,IAAI,QAAiB,CAAC;QACtB,IAAI,CAAC;YACH,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACrD,CAAC;gBACO,CAAC;YACP,WAAW,GAAG,KAAK,CAAC;QACtB,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE;YAAE,MAAM,CAAC,OAAO,EAAE,CAAC;QAC7C,IAAI,MAAM,KAAK,MAAM,IAAI,QAAQ;YAAE,aAAa,CAAC,OAAO,EAAE,CAAC,CAAC;IAC9D,CAAC;IAED,MAAM,OAAO,GAAkB;QAC7B,QAAQ;QACR,IAAI,MAAM;YACR,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,cAAc,EAAE,IAAI,CAAC,cAAc;QACnC,MAAM,CAAC,OAAO;YACZ,IAAI,CAAC,mBAAmB,IAAI,OAAO,IAAI,cAAc,CAAC,OAAO,CAAC;gBAAE,UAAU,EAAE,CAAC;QAC/E,CAAC;QACD,MAAM;QACN,MAAM;YACJ,MAAM,GAAG,MAAM,CAAC;YAChB,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACvB,aAAa,CAAC,OAAO,EAAE,CAAC,CAAC;QAC3B,CAAC;QACD,IAAI,CAAC,OAAO;YACV,MAAM,GAAG,MAAM,CAAC;YAChB,IAAI,OAAO,KAAK,SAAS;gBAAE,WAAW,EAAE,CAAC;;gBACpC,aAAa,CAAC,OAAO,EAAE,GAAG,OAAO,CAAC,CAAC;QAC1C,CAAC;QACD,MAAM;YACJ,MAAM,GAAG,MAAM,CAAC;QAClB,CAAC;QACD,IAAI;YACF,YAAY,GAAG,KAAK,CAAC;YACrB,MAAM,GAAG,MAAM,CAAC;YAChB,WAAW,EAAE,CAAC;QAChB,CAAC;KACF,CAAC;IACF,MAAM,MAAM,GAAG,OAAO,CAAC,gBAAgB,KAAK,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;IAEzG,OAAO;QACL,IAAI,IAAI;YACN,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,aAAa;YACf,OAAO,aAAa,CAAC;QACvB,CAAC;QACD,IAAI,aAAa;YACf,OAAO,aAAa,CAAC;QACvB,CAAC;QACD,KAAK;YACH,mBAAmB,GAAG,KAAK,CAAC;YAC5B,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE;gBAAE,OAAO;YACnC,IAAI,MAAM,KAAK,MAAM;gBAAE,MAAM,CAAC,KAAK,EAAE,CAAC;iBACjC,IAAI,MAAM,KAAK,MAAM,IAAI,UAAU,KAAK,SAAS,IAAI,CAAC,WAAW;gBAAE,QAAQ,EAAE,CAAC;QACrF,CAAC;QACD,IAAI;YACF,mBAAmB,GAAG,KAAK,CAAC;YAC5B,MAAM,CAAC,IAAI,EAAE,CAAC;QAChB,CAAC;QACD,KAAK;YACH,MAAM,CAAC,IAAI,EAAE,CAAC;YACd,UAAU,GAAG,CAAC,CAAC;YACf,mBAAmB,GAAG,IAAI,CAAC;QAC7B,CAAC;QACD,OAAO;YACL,mBAAmB,GAAG,KAAK,CAAC;YAC5B,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,CAAC;QACD,OAAO;YACL,IAAI,WAAW,IAAI,WAAW,EAAE,KAAK,CAAC;gBAAE,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC/D,OAAO,MAAM,CAAC,OAAO,EAAE,CAAC;QAC1B,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -1,47 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
};
|
|
8
|
-
export type RateStrategyObservation = Readonly<{
|
|
9
|
-
currentRate: number;
|
|
10
|
-
minRate: number;
|
|
11
|
-
maxRate: number;
|
|
12
|
-
errorCount: number;
|
|
13
|
-
errorThreshold: number;
|
|
14
|
-
hasPendingWork: boolean;
|
|
15
|
-
wasBackedOff: boolean;
|
|
16
|
-
}>;
|
|
17
|
-
export type RateStrategyDecision = Readonly<{
|
|
18
|
-
nextRate: number;
|
|
19
|
-
shouldBackOff: boolean;
|
|
20
|
-
}>;
|
|
21
|
-
export type RateStrategy = (observation: RateStrategyObservation) => RateStrategyDecision;
|
|
22
|
-
export type AimdOptions = {
|
|
23
|
-
increaseBy?: number;
|
|
24
|
-
decreaseFactor?: number;
|
|
25
|
-
};
|
|
26
|
-
export type RateFailureOutcome = Readonly<{
|
|
27
|
-
kind: "returned-false";
|
|
28
|
-
}> | Readonly<{
|
|
29
|
-
kind: "thrown";
|
|
30
|
-
error: unknown;
|
|
31
|
-
}> | Readonly<{
|
|
32
|
-
kind: "rejected";
|
|
33
|
-
error: unknown;
|
|
34
|
-
}>;
|
|
35
|
-
export type RateOutcomeClassifier = (outcome: RateFailureOutcome) => boolean;
|
|
36
|
-
export type RetryClassifier = (outcome: RateFailureOutcome, attempt: number) => boolean;
|
|
37
|
-
export type AdjustmentTiming = "interval" | "settled";
|
|
38
|
-
export declare const linear: RateStrategy;
|
|
39
|
-
export declare function aimd({ increaseBy, decreaseFactor }?: AimdOptions): RateStrategy;
|
|
40
|
-
export type ExecutionContext = Readonly<{
|
|
41
|
-
signal: AbortSignal;
|
|
42
|
-
}>;
|
|
43
|
-
/** Return `false` to signal failure (increments error count, triggers retry if configured). */
|
|
44
|
-
export type ThrottleCallback = (context: ExecutionContext) => boolean | void | Promise<boolean | void>;
|
|
1
|
+
import type { AdjustmentTiming, RateOutcomeClassifier, RateStrategy } from "./adaptive-rate.js";
|
|
2
|
+
import type { RetryBackoff, RetryClassifier } from "./retry-policy.js";
|
|
3
|
+
import type { ThrottleHandle } from "./scheduler.js";
|
|
4
|
+
export { aimd, linear } from "./adaptive-rate.js";
|
|
5
|
+
export type { AdjustmentTiming, AimdOptions, FailureOutcome, RateOutcomeClassifier, RateStrategy, RateStrategyDecision, RateStrategyObservation } from "./adaptive-rate.js";
|
|
6
|
+
export type { RetryBackoff, RetryClassifier } from "./retry-policy.js";
|
|
7
|
+
export type { ExecutionContext, QueueLifecycleState, QueueState, TaskCallback, TaskHandle, ThrottleCallback, ThrottleFn, ThrottleHandle } from "./scheduler.js";
|
|
45
8
|
export type ThrottleOptions = {
|
|
46
9
|
min_rpi: number;
|
|
47
10
|
interval: number;
|
|
@@ -58,6 +21,8 @@ export type ThrottleOptions = {
|
|
|
58
21
|
concurrency?: number;
|
|
59
22
|
/** Maximum accepted callbacks that have not reached a terminal outcome. Omit for no limit. */
|
|
60
23
|
maxQueueSize?: number;
|
|
24
|
+
/** Longest cooldown, in ms, that `cooldownFor()` applies; longer requests are clamped. Default and maximum 2147483647. */
|
|
25
|
+
maxCooldown?: number;
|
|
61
26
|
/** Non-negative integer dead slots before queue compaction triggers. Default 512. */
|
|
62
27
|
compact_threshold?: number;
|
|
63
28
|
/** Policy used to request the next rate and any backoff after each observation window. */
|
|
@@ -70,27 +35,4 @@ export type ThrottleOptions = {
|
|
|
70
35
|
adjustmentTiming?: AdjustmentTiming;
|
|
71
36
|
onRateChange?: (rate: number) => void;
|
|
72
37
|
};
|
|
73
|
-
export type ThrottleFn = (callback: ThrottleCallback) => void;
|
|
74
|
-
export type QueueLifecycleState = "running" | "paused" | "stopped" | "aborted" | "failed";
|
|
75
|
-
export type QueueState = Readonly<{
|
|
76
|
-
rate: number;
|
|
77
|
-
pending: number;
|
|
78
|
-
active: number;
|
|
79
|
-
state: QueueLifecycleState;
|
|
80
|
-
started: number;
|
|
81
|
-
succeeded: number;
|
|
82
|
-
failed: number;
|
|
83
|
-
retried: number;
|
|
84
|
-
rateIncreases: number;
|
|
85
|
-
rateDecreases: number;
|
|
86
|
-
}>;
|
|
87
|
-
export type ThrottleHandle = ThrottleFn & {
|
|
88
|
-
pause: () => void;
|
|
89
|
-
resume: () => void;
|
|
90
|
-
stop: () => void;
|
|
91
|
-
abort: () => void;
|
|
92
|
-
waitForIdle: () => Promise<void>;
|
|
93
|
-
getState: () => QueueState;
|
|
94
|
-
readonly pending: number;
|
|
95
|
-
};
|
|
96
38
|
export declare function createThrottledQueue(options: ThrottleOptions): ThrottleHandle;
|
|
@@ -1,46 +1,13 @@
|
|
|
1
|
+
import { linear } from "./adaptive-rate.js";
|
|
2
|
+
import { createRetryPolicy } from "./retry-policy.js";
|
|
1
3
|
import { createScheduler } from "./scheduler.js";
|
|
4
|
+
// eslint-disable-next-line no-barrel-files/no-barrel-files -- The package entry exposes the rate strategies owned by the adaptive-rate module.
|
|
5
|
+
export { aimd, linear } from "./adaptive-rate.js";
|
|
2
6
|
const adjustmentTimings = new Set(["interval", "settled"]);
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
return { nextRate: Math.max(minRate, currentRate - 1), shouldBackOff: true };
|
|
6
|
-
}
|
|
7
|
-
if (!wasBackedOff && errorCount === 0 && hasPendingWork) {
|
|
8
|
-
return { nextRate: Math.min(maxRate, currentRate + 1), shouldBackOff: false };
|
|
9
|
-
}
|
|
10
|
-
return { nextRate: currentRate, shouldBackOff: false };
|
|
11
|
-
};
|
|
12
|
-
export function aimd({ increaseBy = 1, decreaseFactor = 0.5 } = {}) {
|
|
13
|
-
if (!Number.isInteger(increaseBy) || increaseBy < 1) {
|
|
14
|
-
throw new Error("increaseBy must be a positive integer");
|
|
15
|
-
}
|
|
16
|
-
if (!Number.isFinite(decreaseFactor) || decreaseFactor <= 0 || decreaseFactor >= 1) {
|
|
17
|
-
throw new Error("decreaseFactor must be a number greater than 0 and less than 1");
|
|
18
|
-
}
|
|
19
|
-
return ({ currentRate, errorCount, errorThreshold, hasPendingWork, wasBackedOff }) => {
|
|
20
|
-
if (errorCount >= errorThreshold) {
|
|
21
|
-
return { nextRate: Math.floor(currentRate * decreaseFactor), shouldBackOff: true };
|
|
22
|
-
}
|
|
23
|
-
if (!wasBackedOff && errorCount === 0 && hasPendingWork) {
|
|
24
|
-
return { nextRate: currentRate + increaseBy, shouldBackOff: false };
|
|
25
|
-
}
|
|
26
|
-
return { nextRate: currentRate, shouldBackOff: false };
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
function validateRetryBackoff(retryBackoff) {
|
|
30
|
-
if (retryBackoff === undefined)
|
|
31
|
-
return;
|
|
32
|
-
if (!Number.isFinite(retryBackoff.baseDelay) || retryBackoff.baseDelay < 0) {
|
|
33
|
-
throw new Error("retryBackoff.baseDelay must be a finite non-negative number");
|
|
34
|
-
}
|
|
35
|
-
if (retryBackoff.maxDelay !== undefined && (!Number.isFinite(retryBackoff.maxDelay) || retryBackoff.maxDelay < 0)) {
|
|
36
|
-
throw new Error("retryBackoff.maxDelay must be a finite non-negative number");
|
|
37
|
-
}
|
|
38
|
-
if (retryBackoff.jitter !== undefined && (!Number.isFinite(retryBackoff.jitter) || retryBackoff.jitter < 0 || retryBackoff.jitter > 1)) {
|
|
39
|
-
throw new Error("retryBackoff.jitter must be a finite number from 0 through 1");
|
|
40
|
-
}
|
|
41
|
-
}
|
|
7
|
+
/** The longest delay `setTimeout` honors; longer delays fire almost immediately. */
|
|
8
|
+
const maxTimerDelay = 2_147_483_647;
|
|
42
9
|
export function createThrottledQueue(options) {
|
|
43
|
-
const { min_rpi, interval, max_rpi = min_rpi, concurrency, maxQueueSize,
|
|
10
|
+
const { min_rpi, interval, max_rpi = min_rpi, concurrency, maxQueueSize, compact_threshold = 512, maxCooldown = maxTimerDelay } = options;
|
|
44
11
|
const errors_per_interval = options.errors_per_interval ?? 5;
|
|
45
12
|
if (!Number.isInteger(min_rpi) || min_rpi < 1) {
|
|
46
13
|
throw new Error("min_rpi must be a positive integer");
|
|
@@ -60,26 +27,32 @@ export function createThrottledQueue(options) {
|
|
|
60
27
|
if (!Number.isInteger(errors_per_interval) || errors_per_interval < 1) {
|
|
61
28
|
throw new Error("errors_per_interval must be a positive integer");
|
|
62
29
|
}
|
|
63
|
-
if (!Number.isInteger(retry) || retry < 0) {
|
|
64
|
-
throw new Error("retry must be a non-negative integer");
|
|
65
|
-
}
|
|
66
30
|
if (!Number.isInteger(compact_threshold) || compact_threshold < 0) {
|
|
67
31
|
throw new Error("compact_threshold must be a non-negative integer");
|
|
68
32
|
}
|
|
33
|
+
if (!Number.isFinite(maxCooldown) || maxCooldown <= 0 || maxCooldown > maxTimerDelay) {
|
|
34
|
+
throw new Error(`maxCooldown must be a positive number no greater than ${maxTimerDelay}`);
|
|
35
|
+
}
|
|
69
36
|
if (options.adjustmentTiming !== undefined && !adjustmentTimings.has(options.adjustmentTiming)) {
|
|
70
37
|
throw new Error("adjustmentTiming must be either interval or settled");
|
|
71
38
|
}
|
|
72
|
-
|
|
73
|
-
return createScheduler(
|
|
74
|
-
|
|
75
|
-
|
|
39
|
+
const retryPolicy = createRetryPolicy(options);
|
|
40
|
+
return createScheduler({
|
|
41
|
+
concurrency: concurrency ?? Infinity,
|
|
42
|
+
capacity: maxQueueSize ?? Infinity,
|
|
43
|
+
compactThreshold: compact_threshold,
|
|
44
|
+
maxCooldown,
|
|
45
|
+
}, {
|
|
46
|
+
minRate: min_rpi,
|
|
47
|
+
maxRate: max_rpi,
|
|
76
48
|
interval,
|
|
77
|
-
|
|
78
|
-
|
|
49
|
+
evenlySpaced: options.evenly_spaced ?? true,
|
|
50
|
+
errorThreshold: errors_per_interval,
|
|
51
|
+
backOff: options.back_off ?? false,
|
|
79
52
|
adjustmentTiming: options.adjustmentTiming ?? "interval",
|
|
80
53
|
rateStrategy: options.rateStrategy ?? linear,
|
|
81
54
|
rateOutcomeClassifier: options.rateOutcomeClassifier,
|
|
82
55
|
onRateChange: options.onRateChange,
|
|
83
|
-
});
|
|
56
|
+
}, retryPolicy);
|
|
84
57
|
}
|
|
85
58
|
//# sourceMappingURL=dynamic-throttled-queue.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dynamic-throttled-queue.js","sourceRoot":"","sources":["../src/dynamic-throttled-queue.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"dynamic-throttled-queue.js","sourceRoot":"","sources":["../src/dynamic-throttled-queue.ts"],"names":[],"mappings":"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"}
|
package/dist/pending-work.d.ts
CHANGED
|
@@ -29,6 +29,8 @@ export type PendingWork<T> = {
|
|
|
29
29
|
accept: (item: T) => void;
|
|
30
30
|
/** Makes the oldest queued item active and returns it, or `undefined` when nothing is queued. */
|
|
31
31
|
take: () => T | undefined;
|
|
32
|
+
/** Drops `item`, which must be queued or held, and releases its reservation. */
|
|
33
|
+
remove: (item: T) => void;
|
|
32
34
|
/**
|
|
33
35
|
* Ends one active item. `decide` runs once the item no longer counts as active but still holds its
|
|
34
36
|
* reservation; returning a retry keeps that reservation, returning nothing releases it. `observe`
|