@dudousxd/nestjs-durable-core 0.82.0 → 0.83.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/dist/index.cjs +76 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +81 -10
- package/dist/index.d.ts +81 -10
- package/dist/index.js +74 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -72,6 +72,7 @@ __export(index_exports, {
|
|
|
72
72
|
ScheduleAlreadyExistsError: () => ScheduleAlreadyExistsError,
|
|
73
73
|
ScheduleClient: () => ScheduleClient,
|
|
74
74
|
ScheduleNotFoundError: () => ScheduleNotFoundError,
|
|
75
|
+
SchemaValidationError: () => SchemaValidationError,
|
|
75
76
|
SignalTimeoutError: () => SignalTimeoutError,
|
|
76
77
|
SingletonQueueFullError: () => SingletonQueueFullError,
|
|
77
78
|
TERMINAL_RUN_STATUSES: () => TERMINAL_RUN_STATUSES,
|
|
@@ -183,6 +184,7 @@ __export(index_exports, {
|
|
|
183
184
|
runStepHandler: () => runStepHandler,
|
|
184
185
|
runValueFacetsFromRuns: () => runValueFacetsFromRuns,
|
|
185
186
|
sanitizeQueueToken: () => sanitizeQueueToken,
|
|
187
|
+
scheduleRunIdAt: () => scheduleRunIdAt,
|
|
186
188
|
scheduledRunId: () => scheduledRunId,
|
|
187
189
|
singletonAdmissionDenialPatch: () => singletonAdmissionDenialPatch,
|
|
188
190
|
singletonAdmissionTags: () => singletonAdmissionTags,
|
|
@@ -481,6 +483,31 @@ var FatalError = class extends Error {
|
|
|
481
483
|
this.details = details;
|
|
482
484
|
}
|
|
483
485
|
};
|
|
486
|
+
var SchemaValidationError = class extends FatalError {
|
|
487
|
+
static {
|
|
488
|
+
__name(this, "SchemaValidationError");
|
|
489
|
+
}
|
|
490
|
+
static code = "schema_validation";
|
|
491
|
+
issues;
|
|
492
|
+
/**
|
|
493
|
+
* @param label What was validated, e.g. `workflow "checkout" input`; the message is
|
|
494
|
+
* `invalid <label>: <path>: <message>; …`.
|
|
495
|
+
* @param summary Overrides the `<path>: <message>; …` part, for issues whose messages already
|
|
496
|
+
* name their field (class-validator's `orderId must be a string`).
|
|
497
|
+
*/
|
|
498
|
+
constructor(label, issues, code = "schema_validation", summary) {
|
|
499
|
+
const normalized = issues.map((issue) => ({
|
|
500
|
+
message: issue.message,
|
|
501
|
+
path: (issue.path ?? []).map((segment) => String(typeof segment === "object" && segment !== null ? segment.key : segment))
|
|
502
|
+
}));
|
|
503
|
+
const text = summary ?? normalized.map((issue) => issue.path.length > 0 ? `${issue.path.join(".")}: ${issue.message}` : issue.message).join("; ");
|
|
504
|
+
super(`invalid ${label}: ${text}`, code, {
|
|
505
|
+
issues: normalized
|
|
506
|
+
});
|
|
507
|
+
this.name = "SchemaValidationError";
|
|
508
|
+
this.issues = normalized;
|
|
509
|
+
}
|
|
510
|
+
};
|
|
484
511
|
var ConcurrencyLimitError = class extends Error {
|
|
485
512
|
static {
|
|
486
513
|
__name(this, "ConcurrencyLimitError");
|
|
@@ -2212,9 +2239,14 @@ function liveHandoff(runId, checkpoints) {
|
|
|
2212
2239
|
return live;
|
|
2213
2240
|
}
|
|
2214
2241
|
__name(liveHandoff, "liveHandoff");
|
|
2242
|
+
var SCHEMA_VALIDATION_CODES = /* @__PURE__ */ new Set([
|
|
2243
|
+
"invalid_input",
|
|
2244
|
+
"invalid_output"
|
|
2245
|
+
]);
|
|
2215
2246
|
function routeFor(routes, error2) {
|
|
2216
2247
|
if (!routes?.length || error2.code && UNROUTABLE_CODES.has(error2.code)) return void 0;
|
|
2217
|
-
|
|
2248
|
+
const { code } = error2;
|
|
2249
|
+
return (code ? routes.find((r) => r.code === code) : void 0) ?? (code && SCHEMA_VALIDATION_CODES.has(code) ? routes.find((r) => r.code === "schema_validation") : void 0) ?? routes.find((r) => r.code === void 0);
|
|
2218
2250
|
}
|
|
2219
2251
|
__name(routeFor, "routeFor");
|
|
2220
2252
|
function assertRoutes(workflow, routes) {
|
|
@@ -2486,9 +2518,13 @@ __name(scheduleRunIdsAt, "scheduleRunIdsAt");
|
|
|
2486
2518
|
async function runSchedules(engine, schedules, nowMs, opts) {
|
|
2487
2519
|
const random = opts?.random ?? Math.random;
|
|
2488
2520
|
const sleep = opts?.sleep ?? defaultSleep;
|
|
2521
|
+
const settled = settledIdsFor(engine);
|
|
2489
2522
|
const ids = [];
|
|
2490
2523
|
for (const s of schedules) {
|
|
2524
|
+
if (engine.isDraining?.()) break;
|
|
2491
2525
|
if (s.paused) continue;
|
|
2526
|
+
const candidates = scheduleRunIdsAt(s, nowMs).filter((id) => !settled.get(s.key)?.has(id));
|
|
2527
|
+
if (candidates.length === 0) continue;
|
|
2492
2528
|
if (s.overlap === "skip" && s.everyMs) {
|
|
2493
2529
|
const prevBucket = Math.floor(nowMs / s.everyMs) - 1;
|
|
2494
2530
|
if (prevBucket >= 0) {
|
|
@@ -2497,14 +2533,44 @@ async function runSchedules(engine, schedules, nowMs, opts) {
|
|
|
2497
2533
|
}
|
|
2498
2534
|
}
|
|
2499
2535
|
if (s.jitter && s.jitter > 0) await sleep(Math.floor(random() * s.jitter));
|
|
2500
|
-
for (const runId of
|
|
2501
|
-
|
|
2536
|
+
for (const runId of candidates) {
|
|
2537
|
+
if (engine.isDraining?.()) break;
|
|
2538
|
+
const existing = await engine.getRun(runId);
|
|
2539
|
+
remember(settled, s.key, runId);
|
|
2540
|
+
if (existing) continue;
|
|
2541
|
+
await engine.start(workflowName(s.workflow), s.input, runId, {
|
|
2542
|
+
namespace: s.namespace
|
|
2543
|
+
});
|
|
2502
2544
|
ids.push(runId);
|
|
2503
2545
|
}
|
|
2504
2546
|
}
|
|
2505
2547
|
return ids;
|
|
2506
2548
|
}
|
|
2507
2549
|
__name(runSchedules, "runSchedules");
|
|
2550
|
+
var settledRunIds = /* @__PURE__ */ new WeakMap();
|
|
2551
|
+
function settledIdsFor(engine) {
|
|
2552
|
+
let memo = settledRunIds.get(engine);
|
|
2553
|
+
if (memo === void 0) {
|
|
2554
|
+
memo = /* @__PURE__ */ new Map();
|
|
2555
|
+
settledRunIds.set(engine, memo);
|
|
2556
|
+
}
|
|
2557
|
+
return memo;
|
|
2558
|
+
}
|
|
2559
|
+
__name(settledIdsFor, "settledIdsFor");
|
|
2560
|
+
function remember(memo, key, runId) {
|
|
2561
|
+
const seen = memo.get(key);
|
|
2562
|
+
if (seen === void 0) {
|
|
2563
|
+
memo.set(key, /* @__PURE__ */ new Set([
|
|
2564
|
+
runId
|
|
2565
|
+
]));
|
|
2566
|
+
return;
|
|
2567
|
+
}
|
|
2568
|
+
seen.add(runId);
|
|
2569
|
+
if (seen.size > 64) memo.set(key, /* @__PURE__ */ new Set([
|
|
2570
|
+
runId
|
|
2571
|
+
]));
|
|
2572
|
+
}
|
|
2573
|
+
__name(remember, "remember");
|
|
2508
2574
|
|
|
2509
2575
|
// src/schedules.ts
|
|
2510
2576
|
var ScheduleAlreadyExistsError = class extends Error {
|
|
@@ -3303,11 +3369,6 @@ function normalizeChildOptions(options) {
|
|
|
3303
3369
|
} : options ?? {};
|
|
3304
3370
|
}
|
|
3305
3371
|
__name(normalizeChildOptions, "normalizeChildOptions");
|
|
3306
|
-
function formatIssuePath(path) {
|
|
3307
|
-
if (!path || path.length === 0) return "(root)";
|
|
3308
|
-
return path.map((segment) => String(typeof segment === "object" ? segment.key : segment)).join(".");
|
|
3309
|
-
}
|
|
3310
|
-
__name(formatIssuePath, "formatIssuePath");
|
|
3311
3372
|
function resolveStepPolicy(config, opts) {
|
|
3312
3373
|
const policy = {};
|
|
3313
3374
|
const retries = opts?.retries ?? config?.retries;
|
|
@@ -4139,11 +4200,7 @@ function createWorkflowCtx(host, runId, compensations, workflow = "", searchAttr
|
|
|
4139
4200
|
throw new Error(`workflow "${workflow}": ctx.upsertSearchAttributes schema validation must be synchronous (the searchAttributes schema's \`~standard.validate\` returned a Promise) \u2014 replay-determinism requires a sync validator; drop any async refinement from the schema passed to @Workflow({ searchAttributes }).`);
|
|
4140
4201
|
}
|
|
4141
4202
|
if (result.issues) {
|
|
4142
|
-
|
|
4143
|
-
...new Set(result.issues.map((issue) => formatIssuePath(issue.path)))
|
|
4144
|
-
];
|
|
4145
|
-
const details = result.issues.map((issue) => `${formatIssuePath(issue.path)}: ${issue.message}`).join("; ");
|
|
4146
|
-
throw new Error(`workflow "${workflow}": ctx.upsertSearchAttributes rejected by its searchAttributes schema \u2014 offending key(s) ${offendingKeys.join(", ")} \u2014 ${details}`);
|
|
4203
|
+
throw new SchemaValidationError(`workflow "${workflow}" ctx.upsertSearchAttributes`, result.issues);
|
|
4147
4204
|
}
|
|
4148
4205
|
}
|
|
4149
4206
|
await host.upsertSearchAttributes(runId, attrs);
|
|
@@ -5349,6 +5406,10 @@ var WorkflowEngine = class {
|
|
|
5349
5406
|
for (const rearm of this.drainRearms) rearm();
|
|
5350
5407
|
}
|
|
5351
5408
|
}
|
|
5409
|
+
/** True once {@link beginDrain} (or {@link drain}) has been called. */
|
|
5410
|
+
isDraining() {
|
|
5411
|
+
return this.draining;
|
|
5412
|
+
}
|
|
5352
5413
|
/**
|
|
5353
5414
|
* Graceful shutdown: stop picking up new runs (recovery/timer become no-ops) and wait for
|
|
5354
5415
|
* in-flight executions to settle, up to `timeoutMs`. Call from your app's shutdown hook so a
|
|
@@ -10940,6 +11001,7 @@ var InMemoryTransport = class {
|
|
|
10940
11001
|
ScheduleAlreadyExistsError,
|
|
10941
11002
|
ScheduleClient,
|
|
10942
11003
|
ScheduleNotFoundError,
|
|
11004
|
+
SchemaValidationError,
|
|
10943
11005
|
SignalTimeoutError,
|
|
10944
11006
|
SingletonQueueFullError,
|
|
10945
11007
|
TERMINAL_RUN_STATUSES,
|
|
@@ -11051,6 +11113,7 @@ var InMemoryTransport = class {
|
|
|
11051
11113
|
runStepHandler,
|
|
11052
11114
|
runValueFacetsFromRuns,
|
|
11053
11115
|
sanitizeQueueToken,
|
|
11116
|
+
scheduleRunIdAt,
|
|
11054
11117
|
scheduledRunId,
|
|
11055
11118
|
singletonAdmissionDenialPatch,
|
|
11056
11119
|
singletonAdmissionTags,
|