dynamic-throttled-queue 2.3.0-rc.494c954 → 2.3.0-rc.b6bb7df
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 +1 -1
- package/dist/adaptive-rate.d.ts +15 -13
- package/dist/adaptive-rate.js +14 -56
- package/dist/adaptive-rate.js.map +1 -1
- package/dist/dynamic-throttled-queue.d.ts +8 -2
- package/dist/dynamic-throttled-queue.js +19 -5
- package/dist/dynamic-throttled-queue.js.map +1 -1
- package/dist/retry-backoff.d.ts +2 -0
- package/dist/retry-backoff.js +31 -0
- package/dist/retry-backoff.js.map +1 -0
- package/dist/scheduler.d.ts +1 -2
- package/dist/scheduler.js +62 -20
- package/dist/scheduler.js.map +1 -1
- package/package.json +5 -5
- package/dist/retry-policy.d.ts +0 -25
- package/dist/retry-policy.js +0 -73
- package/dist/retry-policy.js.map +0 -1
package/README.md
CHANGED
|
@@ -62,7 +62,7 @@ Set `maxQueueSize` to bound accepted work. Capacity is reserved from enqueue thr
|
|
|
62
62
|
| `retryClassifier` | `RetryClassifier` | — | Decides whether a failed callback outcome is eligible for another attempt |
|
|
63
63
|
| `onRateChange` | `(rate: number) => void` | — | Called when the current rate changes |
|
|
64
64
|
|
|
65
|
-
`retry`, `errors_per_interval`, `compact_threshold`, and `maxQueueSize` reject fractional and non-finite values. `errors_per_interval` must be at least `1`; `retry` and `compact_threshold` may be `0`. `retryBackoff.
|
|
65
|
+
`retry`, `errors_per_interval`, `compact_threshold`, and `maxQueueSize` reject fractional and non-finite values. `errors_per_interval` must be at least `1`; `retry` and `compact_threshold` may be `0`. `retryBackoff.baseDelay` and optional `maxDelay` are finite non-negative millisecond values (fractional values are accepted); optional `jitter` is finite from `0` through `1`.
|
|
66
66
|
|
|
67
67
|
`retryBackoff` is `{ strategy: "fixed" | "linear" | "exponential"; baseDelay: number; maxDelay?: number; jitter?: number; random?: () => number }`. The first retry has index `1`: fixed uses `baseDelay`, linear uses `baseDelay × retryIndex`, and exponential uses `baseDelay × 2^(retryIndex - 1)`. The calculated delay is capped at `maxDelay`, when supplied, then optional symmetric percentage jitter is applied and capped again. `random` makes jitter deterministic for tests; a thrown, non-finite, or out-of-range result safely falls back to no jitter. Retry backoff begins when the failed attempt settles and is independent of adaptive-rate `back_off`.
|
|
68
68
|
|
package/dist/adaptive-rate.d.ts
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import type { AdjustmentTiming, RateFailureOutcome, RateOutcomeClassifier, RateStrategy } from "./dynamic-throttled-queue.js";
|
|
2
|
+
/**
|
|
3
|
+
* Whether callbacks may start. `open` allows paced starts, `held` blocks starts until the module
|
|
4
|
+
* reopens them, and `idle` means the module is not observing and waits for `start()`.
|
|
5
|
+
*/
|
|
6
|
+
export type Pacing = "idle" | "open" | "held";
|
|
2
7
|
/** Reports how one started callback settled: `undefined` for success, otherwise the failure. */
|
|
3
8
|
export type SettlementReporter = (outcome: RateFailureOutcome | undefined) => void;
|
|
4
9
|
export type AdaptiveRateOptions = {
|
|
5
10
|
min_rpi: number;
|
|
6
11
|
max_rpi: number;
|
|
7
12
|
interval: number;
|
|
8
|
-
/** Makes one start due every `interval / rate` ms instead of `rate` starts once per interval. */
|
|
9
|
-
evenly_spaced: boolean;
|
|
10
13
|
errors_per_interval: number;
|
|
11
14
|
back_off: boolean;
|
|
12
15
|
adjustmentTiming: AdjustmentTiming;
|
|
@@ -17,12 +20,12 @@ export type AdaptiveRateOptions = {
|
|
|
17
20
|
export type AdaptiveRateHost = {
|
|
18
21
|
/** Whether accepted work is waiting to start. */
|
|
19
22
|
hasPendingWork: () => boolean;
|
|
20
|
-
/**
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
/** Begins fresh pacing: the next paced start is one spacing from now. */
|
|
24
|
+
resumeStarts: () => void;
|
|
25
|
+
/** Cancels the next paced start, or reschedules it `deferBy` ms beyond one spacing from now. */
|
|
26
|
+
holdStarts: (deferBy?: number) => void;
|
|
27
|
+
/** Observation ended: cancel the next paced start. */
|
|
28
|
+
idle: () => void;
|
|
26
29
|
/** The rate strategy failed; the host must call `stop()`. The error is rethrown after this returns. */
|
|
27
30
|
failed: (error: unknown) => void;
|
|
28
31
|
};
|
|
@@ -30,12 +33,11 @@ export type AdaptiveRate = {
|
|
|
30
33
|
readonly rate: number;
|
|
31
34
|
readonly rateIncreases: number;
|
|
32
35
|
readonly rateDecreases: number;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
* is scheduled (concurrency was full), makes starts due now once a spacing has passed since the last
|
|
36
|
-
* start, or schedules them for when it has. During `startsDue`, the batch's own follow-up covers it.
|
|
37
|
-
*/
|
|
36
|
+
readonly pacing: Pacing;
|
|
37
|
+
/** Ends a pause, then begins observing if idle and work is pending. */
|
|
38
38
|
start: () => void;
|
|
39
|
+
/** Reports that every queued callback has started. */
|
|
40
|
+
drained: () => void;
|
|
39
41
|
/** Ends observation. Settled timing discards its in-progress window. */
|
|
40
42
|
stop: () => void;
|
|
41
43
|
/** Stops and discards the observation. Settlements are ignored until `start()` or `stop()`. */
|
package/dist/adaptive-rate.js
CHANGED
|
@@ -114,7 +114,7 @@ function settledTiming(context) {
|
|
|
114
114
|
};
|
|
115
115
|
}
|
|
116
116
|
export function createAdaptiveRate(options, host) {
|
|
117
|
-
const { min_rpi, max_rpi,
|
|
117
|
+
const { min_rpi, max_rpi, errors_per_interval, back_off, rateStrategy, rateOutcomeClassifier, onRateChange } = options;
|
|
118
118
|
let rate = Math.ceil((max_rpi + min_rpi) / 2);
|
|
119
119
|
let rateIncreases = 0;
|
|
120
120
|
let rateDecreases = 0;
|
|
@@ -122,10 +122,6 @@ export function createAdaptiveRate(options, host) {
|
|
|
122
122
|
let wasBackedOff = false;
|
|
123
123
|
let ignoringSettlements = false;
|
|
124
124
|
let pacing = "idle";
|
|
125
|
-
let lastStart = 0;
|
|
126
|
-
let startTimer;
|
|
127
|
-
let dispatching = false;
|
|
128
|
-
let batchStarts = 0;
|
|
129
125
|
function isRateReducing(outcome) {
|
|
130
126
|
try {
|
|
131
127
|
return rateOutcomeClassifier?.(outcome) ?? true;
|
|
@@ -168,41 +164,8 @@ export function createAdaptiveRate(options, host) {
|
|
|
168
164
|
applyRate(Math.min(max_rpi, Math.max(min_rpi, decision.nextRate)));
|
|
169
165
|
return hold;
|
|
170
166
|
}
|
|
171
|
-
function spacing() {
|
|
172
|
-
return evenly_spaced ? interval / rate : interval;
|
|
173
|
-
}
|
|
174
|
-
function scheduleStart(delay) {
|
|
175
|
-
clearTimeout(startTimer);
|
|
176
|
-
startTimer = setTimeout(startDue, delay);
|
|
177
|
-
}
|
|
178
|
-
function cancelStart() {
|
|
179
|
-
clearTimeout(startTimer);
|
|
180
|
-
startTimer = undefined;
|
|
181
|
-
}
|
|
182
|
-
/** Makes a batch of starts due once one spacing has passed since the last start. */
|
|
183
|
-
function startDue() {
|
|
184
|
-
startTimer = undefined;
|
|
185
|
-
const wait = lastStart + spacing() - Date.now();
|
|
186
|
-
if (wait > 0) {
|
|
187
|
-
scheduleStart(wait);
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
190
|
-
dispatching = true;
|
|
191
|
-
batchStarts = 0;
|
|
192
|
-
let slotFree;
|
|
193
|
-
try {
|
|
194
|
-
slotFree = host.startsDue(evenly_spaced ? 1 : rate);
|
|
195
|
-
}
|
|
196
|
-
finally {
|
|
197
|
-
dispatching = false;
|
|
198
|
-
}
|
|
199
|
-
if (!host.hasPendingWork())
|
|
200
|
-
timing.drained();
|
|
201
|
-
if (pacing === "open" && slotFree)
|
|
202
|
-
scheduleStart(spacing());
|
|
203
|
-
}
|
|
204
167
|
const context = {
|
|
205
|
-
interval,
|
|
168
|
+
interval: options.interval,
|
|
206
169
|
get pacing() {
|
|
207
170
|
return pacing;
|
|
208
171
|
},
|
|
@@ -214,15 +177,11 @@ export function createAdaptiveRate(options, host) {
|
|
|
214
177
|
decide,
|
|
215
178
|
resume() {
|
|
216
179
|
pacing = "open";
|
|
217
|
-
|
|
218
|
-
scheduleStart(spacing());
|
|
180
|
+
host.resumeStarts();
|
|
219
181
|
},
|
|
220
182
|
hold(deferBy) {
|
|
221
183
|
pacing = "held";
|
|
222
|
-
|
|
223
|
-
cancelStart();
|
|
224
|
-
else
|
|
225
|
-
scheduleStart(spacing() + deferBy);
|
|
184
|
+
host.holdStarts(deferBy);
|
|
226
185
|
},
|
|
227
186
|
reopen() {
|
|
228
187
|
pacing = "open";
|
|
@@ -230,7 +189,7 @@ export function createAdaptiveRate(options, host) {
|
|
|
230
189
|
idle() {
|
|
231
190
|
wasBackedOff = false;
|
|
232
191
|
pacing = "idle";
|
|
233
|
-
|
|
192
|
+
host.idle();
|
|
234
193
|
},
|
|
235
194
|
};
|
|
236
195
|
const timing = options.adjustmentTiming === "settled" ? settledTiming(context) : intervalTiming(context);
|
|
@@ -244,14 +203,17 @@ export function createAdaptiveRate(options, host) {
|
|
|
244
203
|
get rateDecreases() {
|
|
245
204
|
return rateDecreases;
|
|
246
205
|
},
|
|
206
|
+
get pacing() {
|
|
207
|
+
return pacing;
|
|
208
|
+
},
|
|
247
209
|
start() {
|
|
248
210
|
ignoringSettlements = false;
|
|
249
|
-
if (!host.hasPendingWork())
|
|
211
|
+
if (pacing !== "idle" || !host.hasPendingWork())
|
|
250
212
|
return;
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
213
|
+
timing.start();
|
|
214
|
+
},
|
|
215
|
+
drained() {
|
|
216
|
+
timing.drained();
|
|
255
217
|
},
|
|
256
218
|
stop() {
|
|
257
219
|
ignoringSettlements = false;
|
|
@@ -262,11 +224,7 @@ export function createAdaptiveRate(options, host) {
|
|
|
262
224
|
errorCount = 0;
|
|
263
225
|
ignoringSettlements = true;
|
|
264
226
|
},
|
|
265
|
-
started()
|
|
266
|
-
if (dispatching && batchStarts++ === 0)
|
|
267
|
-
lastStart = Date.now();
|
|
268
|
-
return timing.started();
|
|
269
|
-
},
|
|
227
|
+
started: () => timing.started(),
|
|
270
228
|
};
|
|
271
229
|
}
|
|
272
230
|
//# 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":"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"}
|
|
@@ -1,5 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
export type RetryBackoff = {
|
|
2
|
+
strategy: "fixed" | "linear" | "exponential";
|
|
3
|
+
baseDelay: number;
|
|
4
|
+
maxDelay?: number;
|
|
5
|
+
jitter?: number;
|
|
6
|
+
random?: () => number;
|
|
7
|
+
};
|
|
3
8
|
export type RateStrategyObservation = Readonly<{
|
|
4
9
|
currentRate: number;
|
|
5
10
|
minRate: number;
|
|
@@ -28,6 +33,7 @@ export type RateFailureOutcome = Readonly<{
|
|
|
28
33
|
error: unknown;
|
|
29
34
|
}>;
|
|
30
35
|
export type RateOutcomeClassifier = (outcome: RateFailureOutcome) => boolean;
|
|
36
|
+
export type RetryClassifier = (outcome: RateFailureOutcome, attempt: number) => boolean;
|
|
31
37
|
export type AdjustmentTiming = "interval" | "settled";
|
|
32
38
|
export declare const linear: RateStrategy;
|
|
33
39
|
export declare function aimd({ increaseBy, decreaseFactor }?: AimdOptions): RateStrategy;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { createRetryPolicy } from "./retry-policy.js";
|
|
2
1
|
import { createScheduler } from "./scheduler.js";
|
|
3
2
|
const adjustmentTimings = new Set(["interval", "settled"]);
|
|
4
3
|
export const linear = ({ minRate, maxRate, currentRate, errorCount, errorThreshold, hasPendingWork, wasBackedOff, }) => {
|
|
@@ -27,8 +26,21 @@ export function aimd({ increaseBy = 1, decreaseFactor = 0.5 } = {}) {
|
|
|
27
26
|
return { nextRate: currentRate, shouldBackOff: false };
|
|
28
27
|
};
|
|
29
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
|
+
}
|
|
30
42
|
export function createThrottledQueue(options) {
|
|
31
|
-
const { min_rpi, interval, max_rpi = min_rpi, concurrency, maxQueueSize, compact_threshold = 512 } = options;
|
|
43
|
+
const { min_rpi, interval, max_rpi = min_rpi, concurrency, maxQueueSize, retry = 0, compact_threshold = 512 } = options;
|
|
32
44
|
const errors_per_interval = options.errors_per_interval ?? 5;
|
|
33
45
|
if (!Number.isInteger(min_rpi) || min_rpi < 1) {
|
|
34
46
|
throw new Error("min_rpi must be a positive integer");
|
|
@@ -48,24 +60,26 @@ export function createThrottledQueue(options) {
|
|
|
48
60
|
if (!Number.isInteger(errors_per_interval) || errors_per_interval < 1) {
|
|
49
61
|
throw new Error("errors_per_interval must be a positive integer");
|
|
50
62
|
}
|
|
63
|
+
if (!Number.isInteger(retry) || retry < 0) {
|
|
64
|
+
throw new Error("retry must be a non-negative integer");
|
|
65
|
+
}
|
|
51
66
|
if (!Number.isInteger(compact_threshold) || compact_threshold < 0) {
|
|
52
67
|
throw new Error("compact_threshold must be a non-negative integer");
|
|
53
68
|
}
|
|
54
69
|
if (options.adjustmentTiming !== undefined && !adjustmentTimings.has(options.adjustmentTiming)) {
|
|
55
70
|
throw new Error("adjustmentTiming must be either interval or settled");
|
|
56
71
|
}
|
|
57
|
-
|
|
72
|
+
validateRetryBackoff(options.retryBackoff);
|
|
58
73
|
return createScheduler(options, {
|
|
59
74
|
min_rpi,
|
|
60
75
|
max_rpi,
|
|
61
76
|
interval,
|
|
62
|
-
evenly_spaced: options.evenly_spaced ?? true,
|
|
63
77
|
errors_per_interval,
|
|
64
78
|
back_off: options.back_off ?? false,
|
|
65
79
|
adjustmentTiming: options.adjustmentTiming ?? "interval",
|
|
66
80
|
rateStrategy: options.rateStrategy ?? linear,
|
|
67
81
|
rateOutcomeClassifier: options.rateOutcomeClassifier,
|
|
68
82
|
onRateChange: options.onRateChange,
|
|
69
|
-
}
|
|
83
|
+
});
|
|
70
84
|
}
|
|
71
85
|
//# 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":"AAAA,OAAO,EAAE,eAAe,EAAE,uBAAuB;AA2CjD,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAS,CAAE,UAAU,EAAE,SAAS,CAAE,CAAC,CAAC;AAErE,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;AAiED,SAAS,oBAAoB,CAAC,YAAsC;IAClE,IAAI,YAAY,KAAK,SAAS;QAAE,OAAO;IACvC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,SAAS,CAAC,IAAI,YAAY,CAAC,SAAS,GAAG,CAAC,EAAE,CAAC;QAC3E,MAAM,IAAI,KAAK,CAAC,6DAA6D,CAAC,CAAC;IACjF,CAAC;IACD,IAAI,YAAY,CAAC,QAAQ,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,QAAQ,CAAC,IAAI,YAAY,CAAC,QAAQ,GAAG,CAAC,CAAC,EAAE,CAAC;QAClH,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAC;IAChF,CAAC;IACD,IAAI,YAAY,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC;QACvI,MAAM,IAAI,KAAK,CAAC,8DAA8D,CAAC,CAAC;IAClF,CAAC;AACH,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,OAAwB;IAC3D,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,KAAK,GAAG,CAAC,EAAE,iBAAiB,GAAG,GAAG,EAAE,GAAG,OAAO,CAAC;IAExH,MAAM,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,IAAI,CAAC,CAAC;IAE7D,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;IACxD,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,OAAO,GAAG,OAAO,EAAE,CAAC;QACpD,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC3D,CAAC;IACD,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;QAClD,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;IACxD,CAAC;IAED,IAAI,WAAW,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,IAAI,WAAW,GAAG,CAAC,CAAC,EAAE,CAAC;QACrF,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;IAC5D,CAAC;IACD,IAAI,YAAY,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,YAAY,CAAC,IAAI,YAAY,GAAG,CAAC,CAAC,EAAE,CAAC;QAC5F,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;IACtE,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,mBAAmB,CAAC,IAAI,mBAAmB,GAAG,CAAC,EAAE,CAAC;QACtE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IACpE,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,iBAAiB,CAAC,IAAI,iBAAiB,GAAG,CAAC,EAAE,CAAC;QAClE,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;IACtE,CAAC;IACD,IAAI,OAAO,CAAC,gBAAgB,KAAK,SAAS,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE,CAAC;QAC/F,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;IACzE,CAAC;IACD,oBAAoB,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAC3C,OAAO,eAAe,CAAC,OAAO,EAAE;QAC9B,OAAO;QACP,OAAO;QACP,QAAQ;QACR,mBAAmB;QACnB,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,KAAK;QACnC,gBAAgB,EAAE,OAAO,CAAC,gBAAgB,IAAI,UAAU;QACxD,YAAY,EAAE,OAAO,CAAC,YAAY,IAAI,MAAM;QAC5C,qBAAqB,EAAE,OAAO,CAAC,qBAAqB;QACpD,YAAY,EAAE,OAAO,CAAC,YAAY;KACnC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
function readRandom(random) {
|
|
2
|
+
try {
|
|
3
|
+
// eslint-disable-next-line sonarjs/pseudo-random -- Default jitter requires a random source.
|
|
4
|
+
const value = random?.() ?? Math.random();
|
|
5
|
+
return Number.isFinite(value) && value >= 0 && value <= 1 ? value : undefined;
|
|
6
|
+
}
|
|
7
|
+
catch {
|
|
8
|
+
return undefined;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export function calculateRetryDelay(policy, retryIndex) {
|
|
12
|
+
let delay;
|
|
13
|
+
switch (policy.strategy) {
|
|
14
|
+
case "linear":
|
|
15
|
+
delay = policy.baseDelay * retryIndex;
|
|
16
|
+
break;
|
|
17
|
+
case "exponential":
|
|
18
|
+
delay = policy.baseDelay * 2 ** (retryIndex - 1);
|
|
19
|
+
break;
|
|
20
|
+
default: delay = policy.baseDelay;
|
|
21
|
+
}
|
|
22
|
+
const cappedDelay = policy.maxDelay === undefined ? delay : Math.min(delay, policy.maxDelay);
|
|
23
|
+
if (policy.jitter === undefined)
|
|
24
|
+
return cappedDelay;
|
|
25
|
+
const random = readRandom(policy.random);
|
|
26
|
+
if (random === undefined)
|
|
27
|
+
return cappedDelay;
|
|
28
|
+
const jitteredDelay = cappedDelay * (1 + (random * 2 - 1) * policy.jitter);
|
|
29
|
+
return policy.maxDelay === undefined ? jitteredDelay : Math.min(jitteredDelay, policy.maxDelay);
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=retry-backoff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry-backoff.js","sourceRoot":"","sources":["../src/retry-backoff.ts"],"names":[],"mappings":"AAEA,SAAS,UAAU,CAAC,MAAkC;IACpD,IAAI,CAAC;QACH,6FAA6F;QAC7F,MAAM,KAAK,GAAG,MAAM,EAAE,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAC1C,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;IAChF,CAAC;IACD,MAAM,CAAC;QACL,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,MAAoB,EAAE,UAAkB;IAC1E,IAAI,KAAa,CAAC;IAClB,QAAQ,MAAM,CAAC,QAAQ,EAAE,CAAC;QACxB,KAAK,QAAQ;YAAE,KAAK,GAAG,MAAM,CAAC,SAAS,GAAG,UAAU,CAAC;YAAC,MAAM;QAC5D,KAAK,aAAa;YAAE,KAAK,GAAG,MAAM,CAAC,SAAS,GAAG,CAAC,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC;YAAC,MAAM;QAC5E,OAAO,CAAC,CAAC,KAAK,GAAG,MAAM,CAAC,SAAS,CAAC;IACpC,CAAC;IACD,MAAM,WAAW,GAAG,MAAM,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC7F,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS;QAAE,OAAO,WAAW,CAAC;IACpD,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACzC,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,WAAW,CAAC;IAC7C,MAAM,aAAa,GAAG,WAAW,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IAC3E,OAAO,MAAM,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;AAClG,CAAC"}
|
package/dist/scheduler.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
1
|
import type { AdaptiveRateOptions } from "./adaptive-rate.js";
|
|
2
2
|
import type { ThrottleHandle, ThrottleOptions } from "./dynamic-throttled-queue.js";
|
|
3
|
-
|
|
4
|
-
export declare function createScheduler(options: ThrottleOptions, adaptiveRateOptions: AdaptiveRateOptions, retryPolicy: RetryPolicy): ThrottleHandle;
|
|
3
|
+
export declare function createScheduler(options: ThrottleOptions, adaptiveRateOptions: AdaptiveRateOptions): ThrottleHandle;
|
package/dist/scheduler.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createAdaptiveRate } from "./adaptive-rate.js";
|
|
2
2
|
import { createPendingWork } from "./pending-work.js";
|
|
3
|
+
import { calculateRetryDelay } from "./retry-backoff.js";
|
|
3
4
|
/** The state each event leads to. An event missing from the current state's row is a no-op. */
|
|
4
5
|
const lifecycleTransitions = {
|
|
5
6
|
running: { pause: "paused", stop: "stopped", abort: "aborted", fail: "failed" },
|
|
@@ -8,8 +9,10 @@ const lifecycleTransitions = {
|
|
|
8
9
|
aborted: {},
|
|
9
10
|
failed: {},
|
|
10
11
|
};
|
|
11
|
-
export function createScheduler(options, adaptiveRateOptions
|
|
12
|
-
const { concurrency, maxQueueSize, compact_threshold = 512, } = options;
|
|
12
|
+
export function createScheduler(options, adaptiveRateOptions) {
|
|
13
|
+
const { interval, evenly_spaced = true, retry = 0, retryBackoff, concurrency, maxQueueSize, compact_threshold = 512, retryClassifier, } = options;
|
|
14
|
+
let last_called = 0;
|
|
15
|
+
let timeout;
|
|
13
16
|
let lifecycle = { state: "running" };
|
|
14
17
|
let cnt_started = 0;
|
|
15
18
|
let cnt_succeeded = 0;
|
|
@@ -20,20 +23,26 @@ export function createScheduler(options, adaptiveRateOptions, retryPolicy) {
|
|
|
20
23
|
const work = createPendingWork({ capacity: maxQueueSize ?? Infinity, compactThreshold: compact_threshold }, { retryQueued: start });
|
|
21
24
|
const adaptiveRate = createAdaptiveRate(adaptiveRateOptions, {
|
|
22
25
|
hasPendingWork: () => work.queued > 0,
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
26
|
+
resumeStarts() {
|
|
27
|
+
last_called = Date.now();
|
|
28
|
+
clearTimeout(timeout);
|
|
29
|
+
timeout = setTimeout(dequeue, spacing());
|
|
30
|
+
},
|
|
31
|
+
holdStarts(deferBy) {
|
|
32
|
+
clearTimeout(timeout);
|
|
33
|
+
timeout = deferBy === undefined ? undefined : setTimeout(dequeue, spacing() + deferBy);
|
|
34
|
+
},
|
|
35
|
+
idle() {
|
|
36
|
+
clearTimeout(timeout);
|
|
37
|
+
timeout = undefined;
|
|
32
38
|
},
|
|
33
39
|
failed(error) {
|
|
34
40
|
transition("fail", error);
|
|
35
41
|
},
|
|
36
42
|
});
|
|
43
|
+
function spacing() {
|
|
44
|
+
return evenly_spaced ? interval / adaptiveRate.rate : interval;
|
|
45
|
+
}
|
|
37
46
|
/** Moves the lifecycle for `event` and runs the cleanup that entering the new state requires. */
|
|
38
47
|
function transition(event, error) {
|
|
39
48
|
const next = lifecycleTransitions[lifecycle.state][event];
|
|
@@ -63,14 +72,24 @@ export function createScheduler(options, adaptiveRateOptions, retryPolicy) {
|
|
|
63
72
|
work.fail(error);
|
|
64
73
|
}
|
|
65
74
|
}
|
|
75
|
+
function isRetryable(item, outcome) {
|
|
76
|
+
if (!outcome || item.retries === 0)
|
|
77
|
+
return false;
|
|
78
|
+
try {
|
|
79
|
+
return retryClassifier ? retryClassifier(outcome, retry - item.retries + 1) === true : true;
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
66
85
|
function nextAttempt(item, outcome) {
|
|
67
|
-
if (!outcome)
|
|
68
|
-
return undefined;
|
|
69
|
-
const decision = retryPolicy.decide(outcome, item.attempt);
|
|
70
|
-
if (!decision)
|
|
86
|
+
if (!isRetryable(item, outcome))
|
|
71
87
|
return undefined;
|
|
72
88
|
cnt_retried++;
|
|
73
|
-
|
|
89
|
+
const retryItem = { fn: item.fn, retries: item.retries - 1 };
|
|
90
|
+
if (retryBackoff === undefined)
|
|
91
|
+
return { item: retryItem };
|
|
92
|
+
return { item: retryItem, delay: calculateRetryDelay(retryBackoff, retry - item.retries + 1) };
|
|
74
93
|
}
|
|
75
94
|
function handleSettlement(item, outcome, reportSettlement, resume = false) {
|
|
76
95
|
if (lifecycle.state === "aborted" || lifecycle.state === "failed") {
|
|
@@ -83,9 +102,8 @@ export function createScheduler(options, adaptiveRateOptions, retryPolicy) {
|
|
|
83
102
|
cnt_succeeded++;
|
|
84
103
|
work.settle(() => nextAttempt(item, outcome), () => {
|
|
85
104
|
reportSettlement(outcome);
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
start();
|
|
105
|
+
if (resume && adaptiveRate.pacing === "open" && work.queued > 0)
|
|
106
|
+
dequeue();
|
|
89
107
|
});
|
|
90
108
|
}
|
|
91
109
|
function execute(item) {
|
|
@@ -105,6 +123,30 @@ export function createScheduler(options, adaptiveRateOptions, retryPolicy) {
|
|
|
105
123
|
}
|
|
106
124
|
handleSettlement(item, result === false ? { kind: "returned-false" } : undefined, reportSettlement);
|
|
107
125
|
}
|
|
126
|
+
function dequeue() {
|
|
127
|
+
const threshold = last_called + spacing();
|
|
128
|
+
const now = Date.now();
|
|
129
|
+
if (now < threshold) {
|
|
130
|
+
clearTimeout(timeout);
|
|
131
|
+
timeout = setTimeout(dequeue, threshold - now);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const batch = Math.min(evenly_spaced ? 1 : adaptiveRate.rate, work.queued);
|
|
135
|
+
let started = 0;
|
|
136
|
+
while (started < batch && work.active < max_concurrency) {
|
|
137
|
+
const item = work.take();
|
|
138
|
+
if (item === undefined)
|
|
139
|
+
break;
|
|
140
|
+
if (started++ === 0)
|
|
141
|
+
last_called = Date.now();
|
|
142
|
+
execute(item);
|
|
143
|
+
}
|
|
144
|
+
if (work.queued === 0)
|
|
145
|
+
adaptiveRate.drained();
|
|
146
|
+
if (adaptiveRate.pacing !== "open" || work.active >= max_concurrency)
|
|
147
|
+
return;
|
|
148
|
+
timeout = setTimeout(dequeue, spacing());
|
|
149
|
+
}
|
|
108
150
|
function start() {
|
|
109
151
|
if (lifecycle.state === "running")
|
|
110
152
|
adaptiveRate.start();
|
|
@@ -114,7 +156,7 @@ export function createScheduler(options, adaptiveRateOptions, retryPolicy) {
|
|
|
114
156
|
throw new Error("Cannot enqueue work after the queue has been aborted");
|
|
115
157
|
if (lifecycle.state === "failed")
|
|
116
158
|
throw lifecycle.error;
|
|
117
|
-
work.accept({ fn: callback,
|
|
159
|
+
work.accept({ fn: callback, retries: retry });
|
|
118
160
|
if (lifecycle.state === "stopped")
|
|
119
161
|
transition("restart");
|
|
120
162
|
else
|
package/dist/scheduler.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../src/scheduler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,2BAA2B;AAGxD,OAAO,EAAE,iBAAiB,EAAE,0BAA0B;
|
|
1
|
+
{"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../src/scheduler.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dynamic-throttled-queue",
|
|
3
|
-
"version": "2.3.0-rc.
|
|
3
|
+
"version": "2.3.0-rc.b6bb7df",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Dynamically throttles arbitrary code to execute between a minimum and maximum number of times per interval. Best for making throttled API requests.",
|
|
6
6
|
"files": [
|
|
@@ -30,20 +30,20 @@
|
|
|
30
30
|
"url": "https://github.com/adrianbrowning/dynamic-throttled-queue/issues"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
|
-
"@commitlint/cli": "
|
|
33
|
+
"@commitlint/cli": "20.0.0",
|
|
34
34
|
"@commitlint/config-conventional": "20.0.0",
|
|
35
|
-
"@gingacodemonkey/config": "^0.0.
|
|
35
|
+
"@gingacodemonkey/config": "^0.0.36",
|
|
36
36
|
"@types/node": "^24.13.3",
|
|
37
37
|
"@varlock/bumpy": "^1.18.1",
|
|
38
38
|
"eslint": "^9.39.5",
|
|
39
|
-
"husky": "9.
|
|
39
|
+
"husky": "9.0.6",
|
|
40
40
|
"jscpd": "^4.2.5",
|
|
41
41
|
"knip": "5.70.1",
|
|
42
42
|
"lint-staged": "17.6.0",
|
|
43
43
|
"only-allow": "^1.2.2",
|
|
44
44
|
"typescript": "^6.0.3",
|
|
45
45
|
"vitest": "^5.0.2",
|
|
46
|
-
"zshy": "^0.
|
|
46
|
+
"zshy": "^0.7.0"
|
|
47
47
|
},
|
|
48
48
|
"engines": {
|
|
49
49
|
"node": ">=24.0.0",
|
package/dist/retry-policy.d.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import type { RateFailureOutcome } from "./dynamic-throttled-queue.js";
|
|
2
|
-
export type RetryBackoff = {
|
|
3
|
-
strategy: "fixed" | "linear" | "exponential";
|
|
4
|
-
baseDelay: number;
|
|
5
|
-
maxDelay?: number;
|
|
6
|
-
jitter?: number;
|
|
7
|
-
random?: () => number;
|
|
8
|
-
};
|
|
9
|
-
export type RetryClassifier = (outcome: RateFailureOutcome, attempt: number) => boolean;
|
|
10
|
-
export type RetryPolicyOptions = {
|
|
11
|
-
retry?: number;
|
|
12
|
-
retryBackoff?: RetryBackoff;
|
|
13
|
-
retryClassifier?: RetryClassifier;
|
|
14
|
-
};
|
|
15
|
-
/** How a failed attempt continues: `{}` retries now, `{ delay }` retries after `delay` ms. */
|
|
16
|
-
type RetryDecision = Readonly<{
|
|
17
|
-
delay?: number;
|
|
18
|
-
}>;
|
|
19
|
-
export type RetryPolicy = {
|
|
20
|
-
/** Decides whether failed attempt `attempt` (one-based) gets another attempt. `undefined` drops it. */
|
|
21
|
-
decide: (outcome: RateFailureOutcome, attempt: number) => RetryDecision | undefined;
|
|
22
|
-
};
|
|
23
|
-
/** Validates the retry options, then decides each failed attempt: drop, retry now, or retry after a delay. */
|
|
24
|
-
export declare function createRetryPolicy({ retry, retryBackoff, retryClassifier }: RetryPolicyOptions): RetryPolicy;
|
|
25
|
-
export {};
|
package/dist/retry-policy.js
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
const strategies = { fixed: true, linear: true, exponential: true };
|
|
2
|
-
const retryNow = Object.freeze({});
|
|
3
|
-
function validate(retry, retryBackoff) {
|
|
4
|
-
if (!Number.isInteger(retry) || retry < 0) {
|
|
5
|
-
throw new Error("retry must be a non-negative integer");
|
|
6
|
-
}
|
|
7
|
-
if (retryBackoff === undefined)
|
|
8
|
-
return;
|
|
9
|
-
if (!Object.hasOwn(strategies, retryBackoff.strategy)) {
|
|
10
|
-
throw new Error("retryBackoff.strategy must be fixed, linear, or exponential");
|
|
11
|
-
}
|
|
12
|
-
if (!Number.isFinite(retryBackoff.baseDelay) || retryBackoff.baseDelay < 0) {
|
|
13
|
-
throw new Error("retryBackoff.baseDelay must be a finite non-negative number");
|
|
14
|
-
}
|
|
15
|
-
if (retryBackoff.maxDelay !== undefined && (!Number.isFinite(retryBackoff.maxDelay) || retryBackoff.maxDelay < 0)) {
|
|
16
|
-
throw new Error("retryBackoff.maxDelay must be a finite non-negative number");
|
|
17
|
-
}
|
|
18
|
-
if (retryBackoff.jitter !== undefined && (!Number.isFinite(retryBackoff.jitter) || retryBackoff.jitter < 0 || retryBackoff.jitter > 1)) {
|
|
19
|
-
throw new Error("retryBackoff.jitter must be a finite number from 0 through 1");
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
function readRandom(random) {
|
|
23
|
-
try {
|
|
24
|
-
// eslint-disable-next-line sonarjs/pseudo-random -- Default jitter requires a random source.
|
|
25
|
-
const value = random?.() ?? Math.random();
|
|
26
|
-
return Number.isFinite(value) && value >= 0 && value <= 1 ? value : undefined;
|
|
27
|
-
}
|
|
28
|
-
catch {
|
|
29
|
-
return undefined;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
function calculateRetryDelay(policy, retryIndex) {
|
|
33
|
-
let delay;
|
|
34
|
-
switch (policy.strategy) {
|
|
35
|
-
case "linear":
|
|
36
|
-
delay = policy.baseDelay * retryIndex;
|
|
37
|
-
break;
|
|
38
|
-
case "exponential":
|
|
39
|
-
delay = policy.baseDelay * 2 ** (retryIndex - 1);
|
|
40
|
-
break;
|
|
41
|
-
default: delay = policy.baseDelay;
|
|
42
|
-
}
|
|
43
|
-
const cappedDelay = policy.maxDelay === undefined ? delay : Math.min(delay, policy.maxDelay);
|
|
44
|
-
if (policy.jitter === undefined)
|
|
45
|
-
return cappedDelay;
|
|
46
|
-
const random = readRandom(policy.random);
|
|
47
|
-
if (random === undefined)
|
|
48
|
-
return cappedDelay;
|
|
49
|
-
const jitteredDelay = cappedDelay * (1 + (random * 2 - 1) * policy.jitter);
|
|
50
|
-
return policy.maxDelay === undefined ? jitteredDelay : Math.min(jitteredDelay, policy.maxDelay);
|
|
51
|
-
}
|
|
52
|
-
/** Validates the retry options, then decides each failed attempt: drop, retry now, or retry after a delay. */
|
|
53
|
-
export function createRetryPolicy({ retry = 0, retryBackoff, retryClassifier }) {
|
|
54
|
-
validate(retry, retryBackoff);
|
|
55
|
-
function isRetryable(outcome, attempt) {
|
|
56
|
-
if (!retryClassifier)
|
|
57
|
-
return true;
|
|
58
|
-
try {
|
|
59
|
-
return retryClassifier(outcome, attempt) === true;
|
|
60
|
-
}
|
|
61
|
-
catch {
|
|
62
|
-
return true;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
return {
|
|
66
|
-
decide(outcome, attempt) {
|
|
67
|
-
if (attempt > retry || !isRetryable(outcome, attempt))
|
|
68
|
-
return undefined;
|
|
69
|
-
return retryBackoff === undefined ? retryNow : { delay: calculateRetryDelay(retryBackoff, attempt) };
|
|
70
|
-
},
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
//# sourceMappingURL=retry-policy.js.map
|
package/dist/retry-policy.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"retry-policy.js","sourceRoot":"","sources":["../src/retry-policy.ts"],"names":[],"mappings":"AA0BA,MAAM,UAAU,GAAqD,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;AACtH,MAAM,QAAQ,GAAkB,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AAElD,SAAS,QAAQ,CAAC,KAAa,EAAE,YAAsC;IACrE,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IACD,IAAI,YAAY,KAAK,SAAS;QAAE,OAAO;IACvC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC;QACtD,MAAM,IAAI,KAAK,CAAC,6DAA6D,CAAC,CAAC;IACjF,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,SAAS,CAAC,IAAI,YAAY,CAAC,SAAS,GAAG,CAAC,EAAE,CAAC;QAC3E,MAAM,IAAI,KAAK,CAAC,6DAA6D,CAAC,CAAC;IACjF,CAAC;IACD,IAAI,YAAY,CAAC,QAAQ,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,QAAQ,CAAC,IAAI,YAAY,CAAC,QAAQ,GAAG,CAAC,CAAC,EAAE,CAAC;QAClH,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAC;IAChF,CAAC;IACD,IAAI,YAAY,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC;QACvI,MAAM,IAAI,KAAK,CAAC,8DAA8D,CAAC,CAAC;IAClF,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,MAAkC;IACpD,IAAI,CAAC;QACH,6FAA6F;QAC7F,MAAM,KAAK,GAAG,MAAM,EAAE,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAC1C,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;IAChF,CAAC;IACD,MAAM,CAAC;QACL,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,SAAS,mBAAmB,CAAC,MAAoB,EAAE,UAAkB;IACnE,IAAI,KAAa,CAAC;IAClB,QAAQ,MAAM,CAAC,QAAQ,EAAE,CAAC;QACxB,KAAK,QAAQ;YAAE,KAAK,GAAG,MAAM,CAAC,SAAS,GAAG,UAAU,CAAC;YAAC,MAAM;QAC5D,KAAK,aAAa;YAAE,KAAK,GAAG,MAAM,CAAC,SAAS,GAAG,CAAC,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC;YAAC,MAAM;QAC5E,OAAO,CAAC,CAAC,KAAK,GAAG,MAAM,CAAC,SAAS,CAAC;IACpC,CAAC;IACD,MAAM,WAAW,GAAG,MAAM,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC7F,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS;QAAE,OAAO,WAAW,CAAC;IACpD,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACzC,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,WAAW,CAAC;IAC7C,MAAM,aAAa,GAAG,WAAW,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IAC3E,OAAO,MAAM,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;AAClG,CAAC;AAED,8GAA8G;AAC9G,MAAM,UAAU,iBAAiB,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,YAAY,EAAE,eAAe,EAAsB;IAChG,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;IAE9B,SAAS,WAAW,CAAC,OAA2B,EAAE,OAAe;QAC/D,IAAI,CAAC,eAAe;YAAE,OAAO,IAAI,CAAC;QAClC,IAAI,CAAC;YACH,OAAO,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;QACpD,CAAC;QACD,MAAM,CAAC;YACL,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,OAAO;QACL,MAAM,CAAC,OAAO,EAAE,OAAO;YACrB,IAAI,OAAO,GAAG,KAAK,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC;gBAAE,OAAO,SAAS,CAAC;YACxE,OAAO,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,mBAAmB,CAAC,YAAY,EAAE,OAAO,CAAC,EAAE,CAAC;QACvG,CAAC;KACF,CAAC;AACJ,CAAC"}
|