@valentinkolb/sync 2.2.0 → 3.0.0
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 +144 -193
- package/browser/ephemeral.js +472 -0
- package/browser/index.js +21 -0
- package/browser/job.js +14687 -0
- package/browser/mutex.js +165 -0
- package/browser/queue.js +342 -0
- package/browser/ratelimit.js +124 -0
- package/browser/registry.js +662 -0
- package/browser/retry.js +94 -0
- package/browser/scheduler.js +988 -0
- package/browser/store.js +61 -0
- package/browser/topic.js +359 -0
- package/index.js +1 -18531
- package/package.json +19 -4
- package/src/browser/ephemeral.d.ts +101 -0
- package/src/browser/index.d.ts +10 -0
- package/src/browser/internal/emitter.d.ts +11 -0
- package/src/browser/internal/event-log.d.ts +33 -0
- package/src/browser/internal/id.d.ts +9 -0
- package/src/browser/internal/sleep.d.ts +2 -0
- package/src/browser/job.d.ts +107 -0
- package/src/browser/mutex.d.ts +28 -0
- package/src/browser/queue.d.ts +67 -0
- package/src/browser/ratelimit.d.ts +24 -0
- package/src/browser/registry.d.ts +131 -0
- package/src/browser/retry.d.ts +19 -0
- package/src/browser/scheduler.d.ts +164 -0
- package/src/browser/store.d.ts +17 -0
- package/src/browser/topic.d.ts +65 -0
package/browser/retry.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// src/browser/internal/sleep.ts
|
|
2
|
+
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
3
|
+
var createAbortError = () => {
|
|
4
|
+
const error = new Error("sleep aborted");
|
|
5
|
+
error.name = "AbortError";
|
|
6
|
+
return error;
|
|
7
|
+
};
|
|
8
|
+
var sleepWithSignal = async (delayMs, signal) => {
|
|
9
|
+
if (delayMs <= 0)
|
|
10
|
+
return;
|
|
11
|
+
if (!signal) {
|
|
12
|
+
await sleep(delayMs);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
if (signal.aborted)
|
|
16
|
+
throw createAbortError();
|
|
17
|
+
await new Promise((resolve, reject) => {
|
|
18
|
+
const timer = setTimeout(() => {
|
|
19
|
+
signal.removeEventListener("abort", onAbort);
|
|
20
|
+
resolve();
|
|
21
|
+
}, delayMs);
|
|
22
|
+
const onAbort = () => {
|
|
23
|
+
clearTimeout(timer);
|
|
24
|
+
signal.removeEventListener("abort", onAbort);
|
|
25
|
+
reject(createAbortError());
|
|
26
|
+
};
|
|
27
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
28
|
+
});
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// src/browser/retry.ts
|
|
32
|
+
var asError = (error) => error instanceof Error ? error : new Error(String(error));
|
|
33
|
+
var createAbortError2 = () => {
|
|
34
|
+
const error = new Error("retry aborted");
|
|
35
|
+
error.name = "AbortError";
|
|
36
|
+
return error;
|
|
37
|
+
};
|
|
38
|
+
var parseCode = (error) => {
|
|
39
|
+
if (!error || typeof error !== "object")
|
|
40
|
+
return "";
|
|
41
|
+
const code = error.code;
|
|
42
|
+
return typeof code === "string" ? code.toUpperCase() : "";
|
|
43
|
+
};
|
|
44
|
+
var isRetryableTransportError = (error) => {
|
|
45
|
+
const code = parseCode(error);
|
|
46
|
+
if (code === "ECONNRESET" || code === "ETIMEDOUT" || code === "ECONNREFUSED" || code === "ENOTFOUND" || code === "EPIPE" || code === "EHOSTUNREACH" || code === "ECONNABORTED") {
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
const message = asError(error).message.toLowerCase();
|
|
50
|
+
return message.includes("econnreset") || message.includes("etimedout") || message.includes("connection") || message.includes("socket") || message.includes("broken pipe") || message.includes("network") || message.includes("loading") || message.includes("tryagain") || message.includes("clusterdown");
|
|
51
|
+
};
|
|
52
|
+
var DEFAULT_RETRY_OPTIONS = {
|
|
53
|
+
attempts: 8,
|
|
54
|
+
minDelayMs: 100,
|
|
55
|
+
maxDelayMs: 2000,
|
|
56
|
+
factor: 2,
|
|
57
|
+
jitter: 0.2,
|
|
58
|
+
retryIf: isRetryableTransportError
|
|
59
|
+
};
|
|
60
|
+
var computeDelayMs = (attempt, opts) => {
|
|
61
|
+
const base = opts.minDelayMs * opts.factor ** Math.max(0, attempt - 1);
|
|
62
|
+
const capped = Math.min(opts.maxDelayMs, base);
|
|
63
|
+
const spread = capped * opts.jitter;
|
|
64
|
+
const jittered = capped + (Math.random() * 2 - 1) * spread;
|
|
65
|
+
return Math.max(0, Math.floor(jittered));
|
|
66
|
+
};
|
|
67
|
+
var retry = async (fn, opts = {}) => {
|
|
68
|
+
const attempts = Math.max(1, opts.attempts ?? DEFAULT_RETRY_OPTIONS.attempts);
|
|
69
|
+
const minDelayMs = Math.max(0, opts.minDelayMs ?? DEFAULT_RETRY_OPTIONS.minDelayMs);
|
|
70
|
+
const maxDelayMs = Math.max(minDelayMs, opts.maxDelayMs ?? DEFAULT_RETRY_OPTIONS.maxDelayMs);
|
|
71
|
+
const factor = Math.max(1, opts.factor ?? DEFAULT_RETRY_OPTIONS.factor);
|
|
72
|
+
const jitter = Math.min(1, Math.max(0, opts.jitter ?? DEFAULT_RETRY_OPTIONS.jitter));
|
|
73
|
+
const retryIf = opts.retryIf ?? DEFAULT_RETRY_OPTIONS.retryIf;
|
|
74
|
+
for (let attempt = 1;attempt <= attempts; attempt++) {
|
|
75
|
+
if (opts.signal?.aborted)
|
|
76
|
+
throw createAbortError2();
|
|
77
|
+
try {
|
|
78
|
+
return await fn(attempt);
|
|
79
|
+
} catch (error) {
|
|
80
|
+
if (attempt >= attempts)
|
|
81
|
+
throw error;
|
|
82
|
+
if (!retryIf(error))
|
|
83
|
+
throw error;
|
|
84
|
+
const delayMs = computeDelayMs(attempt, { minDelayMs, maxDelayMs, factor, jitter });
|
|
85
|
+
await sleepWithSignal(delayMs, opts.signal);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
throw new Error("unreachable retry state");
|
|
89
|
+
};
|
|
90
|
+
export {
|
|
91
|
+
retry,
|
|
92
|
+
isRetryableTransportError,
|
|
93
|
+
DEFAULT_RETRY_OPTIONS
|
|
94
|
+
};
|