@dudousxd/nestjs-durable-core 0.85.0 → 0.85.1
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/dist/index.cjs +36 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -3
- package/dist/index.d.ts +9 -3
- package/dist/index.js +36 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -7038,6 +7038,8 @@ interface ScheduledWorkflow<W extends WorkflowRef = WorkflowRef> {
|
|
|
7038
7038
|
/**
|
|
7039
7039
|
* Randomly delay the dispatch by up to this many ms BEFORE firing, to spread load when many
|
|
7040
7040
|
* instances tick on the same boundary (avoids a thundering herd). Opt-in; absent = fire immediately.
|
|
7041
|
+
* The window is deferred to a later tick, never waited for inside one, so a jittered schedule does
|
|
7042
|
+
* not hold up any other schedule or the rest of the timer poll.
|
|
7041
7043
|
*
|
|
7042
7044
|
* This is dispatch-path jitter only — it does NOT affect the run id (still the time bucket), so
|
|
7043
7045
|
* idempotency is unchanged: two instances jittering the same window still start it exactly once.
|
|
@@ -7066,9 +7068,13 @@ interface ScheduledWorkflow<W extends WorkflowRef = WorkflowRef> {
|
|
|
7066
7068
|
namespace?: string;
|
|
7067
7069
|
}
|
|
7068
7070
|
/** Injectable dispatch-path effects (kept out of the deterministic run-id logic). Defaults to real
|
|
7069
|
-
* `Math.random
|
|
7071
|
+
* `Math.random`; overridden in tests so jitter is deterministic. */
|
|
7070
7072
|
interface RunSchedulesOptions {
|
|
7071
7073
|
random?: () => number;
|
|
7074
|
+
/**
|
|
7075
|
+
* @deprecated No longer called: jitter defers a window to a later tick instead of sleeping inside
|
|
7076
|
+
* this one. Kept so existing callers still type-check.
|
|
7077
|
+
*/
|
|
7072
7078
|
sleep?: (ms: number) => Promise<void>;
|
|
7073
7079
|
}
|
|
7074
7080
|
/** Deterministic run id for a fixed-interval schedule's current time window. */
|
|
@@ -7098,8 +7104,8 @@ declare function scheduleRunIdAt(s: ScheduledWorkflow, nowMs: number): string;
|
|
|
7098
7104
|
* racing two instances on the same tick — starts **each window exactly once**. Wire it to a
|
|
7099
7105
|
* `setInterval`, the durable timer poller, or `@nestjs/schedule`. Returns the run ids this call
|
|
7100
7106
|
* started: a window that already has a run is not started or returned again, and once this process
|
|
7101
|
-
* has seen a window's run exist, later calls in that window skip it without a store read
|
|
7102
|
-
*
|
|
7107
|
+
* has seen a window's run exist, later calls in that window skip it without a store read. A
|
|
7108
|
+
* jittered window is deferred to a later call, never slept on.
|
|
7103
7109
|
*/
|
|
7104
7110
|
declare function runSchedules(engine: Pick<WorkflowEngine, 'start' | 'getRun'> & Partial<Pick<WorkflowEngine, 'isDraining'>>, schedules: readonly ScheduledWorkflow[], nowMs: number, opts?: RunSchedulesOptions): Promise<string[]>;
|
|
7105
7111
|
|
package/dist/index.d.ts
CHANGED
|
@@ -7038,6 +7038,8 @@ interface ScheduledWorkflow<W extends WorkflowRef = WorkflowRef> {
|
|
|
7038
7038
|
/**
|
|
7039
7039
|
* Randomly delay the dispatch by up to this many ms BEFORE firing, to spread load when many
|
|
7040
7040
|
* instances tick on the same boundary (avoids a thundering herd). Opt-in; absent = fire immediately.
|
|
7041
|
+
* The window is deferred to a later tick, never waited for inside one, so a jittered schedule does
|
|
7042
|
+
* not hold up any other schedule or the rest of the timer poll.
|
|
7041
7043
|
*
|
|
7042
7044
|
* This is dispatch-path jitter only — it does NOT affect the run id (still the time bucket), so
|
|
7043
7045
|
* idempotency is unchanged: two instances jittering the same window still start it exactly once.
|
|
@@ -7066,9 +7068,13 @@ interface ScheduledWorkflow<W extends WorkflowRef = WorkflowRef> {
|
|
|
7066
7068
|
namespace?: string;
|
|
7067
7069
|
}
|
|
7068
7070
|
/** Injectable dispatch-path effects (kept out of the deterministic run-id logic). Defaults to real
|
|
7069
|
-
* `Math.random
|
|
7071
|
+
* `Math.random`; overridden in tests so jitter is deterministic. */
|
|
7070
7072
|
interface RunSchedulesOptions {
|
|
7071
7073
|
random?: () => number;
|
|
7074
|
+
/**
|
|
7075
|
+
* @deprecated No longer called: jitter defers a window to a later tick instead of sleeping inside
|
|
7076
|
+
* this one. Kept so existing callers still type-check.
|
|
7077
|
+
*/
|
|
7072
7078
|
sleep?: (ms: number) => Promise<void>;
|
|
7073
7079
|
}
|
|
7074
7080
|
/** Deterministic run id for a fixed-interval schedule's current time window. */
|
|
@@ -7098,8 +7104,8 @@ declare function scheduleRunIdAt(s: ScheduledWorkflow, nowMs: number): string;
|
|
|
7098
7104
|
* racing two instances on the same tick — starts **each window exactly once**. Wire it to a
|
|
7099
7105
|
* `setInterval`, the durable timer poller, or `@nestjs/schedule`. Returns the run ids this call
|
|
7100
7106
|
* started: a window that already has a run is not started or returned again, and once this process
|
|
7101
|
-
* has seen a window's run exist, later calls in that window skip it without a store read
|
|
7102
|
-
*
|
|
7107
|
+
* has seen a window's run exist, later calls in that window skip it without a store read. A
|
|
7108
|
+
* jittered window is deferred to a later call, never slept on.
|
|
7103
7109
|
*/
|
|
7104
7110
|
declare function runSchedules(engine: Pick<WorkflowEngine, 'start' | 'getRun'> & Partial<Pick<WorkflowEngine, 'isDraining'>>, schedules: readonly ScheduledWorkflow[], nowMs: number, opts?: RunSchedulesOptions): Promise<string[]>;
|
|
7105
7111
|
|
package/dist/index.js
CHANGED
|
@@ -2417,7 +2417,31 @@ __name(resolveCronParse, "resolveCronParse");
|
|
|
2417
2417
|
|
|
2418
2418
|
// src/scheduler.ts
|
|
2419
2419
|
var nodeRequire = createRequire(import.meta.url);
|
|
2420
|
-
var
|
|
2420
|
+
var jitterFireAt = /* @__PURE__ */ new WeakMap();
|
|
2421
|
+
function deferredWindows(engine, key) {
|
|
2422
|
+
return [
|
|
2423
|
+
...jitterFireAt.get(engine)?.get(key)?.keys() ?? []
|
|
2424
|
+
];
|
|
2425
|
+
}
|
|
2426
|
+
__name(deferredWindows, "deferredWindows");
|
|
2427
|
+
function jitterDue(engine, s, candidates, nowMs, random) {
|
|
2428
|
+
let byKey = jitterFireAt.get(engine);
|
|
2429
|
+
if (byKey === void 0) {
|
|
2430
|
+
byKey = /* @__PURE__ */ new Map();
|
|
2431
|
+
jitterFireAt.set(engine, byKey);
|
|
2432
|
+
}
|
|
2433
|
+
const previous = byKey.get(s.key);
|
|
2434
|
+
const current = /* @__PURE__ */ new Map();
|
|
2435
|
+
const due = [];
|
|
2436
|
+
for (const runId of candidates) {
|
|
2437
|
+
const at = previous?.get(runId) ?? nowMs + Math.floor(random() * s.jitter);
|
|
2438
|
+
if (nowMs >= at) due.push(runId);
|
|
2439
|
+
else current.set(runId, at);
|
|
2440
|
+
}
|
|
2441
|
+
byKey.set(s.key, current);
|
|
2442
|
+
return due;
|
|
2443
|
+
}
|
|
2444
|
+
__name(jitterDue, "jitterDue");
|
|
2421
2445
|
function scheduledRunId(key, everyMs, nowMs) {
|
|
2422
2446
|
return `sched:${key}:${Math.floor(nowMs / everyMs)}`;
|
|
2423
2447
|
}
|
|
@@ -2487,13 +2511,19 @@ function scheduleRunIdsAt(s, nowMs) {
|
|
|
2487
2511
|
__name(scheduleRunIdsAt, "scheduleRunIdsAt");
|
|
2488
2512
|
async function runSchedules(engine, schedules, nowMs, opts) {
|
|
2489
2513
|
const random = opts?.random ?? Math.random;
|
|
2490
|
-
const sleep = opts?.sleep ?? defaultSleep;
|
|
2491
2514
|
const settled = settledIdsFor(engine);
|
|
2492
2515
|
const ids = [];
|
|
2493
2516
|
for (const s of schedules) {
|
|
2494
2517
|
if (engine.isDraining?.()) break;
|
|
2495
2518
|
if (s.paused) continue;
|
|
2496
|
-
const
|
|
2519
|
+
const due = scheduleRunIdsAt(s, nowMs);
|
|
2520
|
+
const windows = s.jitter && s.jitter > 0 ? [
|
|
2521
|
+
.../* @__PURE__ */ new Set([
|
|
2522
|
+
...deferredWindows(engine, s.key),
|
|
2523
|
+
...due
|
|
2524
|
+
])
|
|
2525
|
+
] : due;
|
|
2526
|
+
const candidates = windows.filter((id) => !settled.get(s.key)?.has(id));
|
|
2497
2527
|
if (candidates.length === 0) continue;
|
|
2498
2528
|
if (s.overlap === "skip" && s.everyMs) {
|
|
2499
2529
|
const prevBucket = Math.floor(nowMs / s.everyMs) - 1;
|
|
@@ -2502,8 +2532,9 @@ async function runSchedules(engine, schedules, nowMs, opts) {
|
|
|
2502
2532
|
if (prev && (prev.status === "running" || prev.status === "suspended")) continue;
|
|
2503
2533
|
}
|
|
2504
2534
|
}
|
|
2505
|
-
|
|
2506
|
-
|
|
2535
|
+
const firing = s.jitter && s.jitter > 0 ? jitterDue(engine, s, candidates, nowMs, random) : candidates;
|
|
2536
|
+
if (firing.length === 0) continue;
|
|
2537
|
+
for (const runId of firing) {
|
|
2507
2538
|
if (engine.isDraining?.()) break;
|
|
2508
2539
|
const existing = await engine.getRun(runId);
|
|
2509
2540
|
remember(settled, s.key, runId);
|