@dudousxd/nestjs-durable-core 0.39.0 → 0.40.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 +63 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +35 -9
- package/dist/index.d.ts +35 -9
- package/dist/index.js +63 -24
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1280,7 +1280,8 @@ function createWorkflowCtx(host, runId, compensations, workflow = "") {
|
|
|
1280
1280
|
await store.putSignalWaiter({
|
|
1281
1281
|
token: `child:${childId}`,
|
|
1282
1282
|
runId,
|
|
1283
|
-
seq
|
|
1283
|
+
seq,
|
|
1284
|
+
parallelGroup: group
|
|
1284
1285
|
});
|
|
1285
1286
|
if (!await store.getRun(childId)) host.startChild(name, inputs[i], childId);
|
|
1286
1287
|
if (!cp) {
|
|
@@ -1512,6 +1513,14 @@ function isNewerVersion(a, b) {
|
|
|
1512
1513
|
}) > 0;
|
|
1513
1514
|
}
|
|
1514
1515
|
__name(isNewerVersion, "isNewerVersion");
|
|
1516
|
+
var NamespaceMismatch = class NamespaceMismatch2 extends Error {
|
|
1517
|
+
static {
|
|
1518
|
+
__name(this, "NamespaceMismatch");
|
|
1519
|
+
}
|
|
1520
|
+
constructor() {
|
|
1521
|
+
super("namespace-mismatch");
|
|
1522
|
+
}
|
|
1523
|
+
};
|
|
1515
1524
|
var WorkflowEngine = class {
|
|
1516
1525
|
static {
|
|
1517
1526
|
__name(this, "WorkflowEngine");
|
|
@@ -1522,6 +1531,7 @@ var WorkflowEngine = class {
|
|
|
1522
1531
|
controlPlane;
|
|
1523
1532
|
clock;
|
|
1524
1533
|
instanceId;
|
|
1534
|
+
namespace;
|
|
1525
1535
|
leaseMs;
|
|
1526
1536
|
maxRecoveryAttempts;
|
|
1527
1537
|
remoteAdvanceSilenceMs;
|
|
@@ -1588,6 +1598,7 @@ var WorkflowEngine = class {
|
|
|
1588
1598
|
this.admission = deps.admission ?? new InMemoryAdmissionBackend(this.clock);
|
|
1589
1599
|
this.admission.onFreed?.((queue) => this.wakeQueueWaiters(queue));
|
|
1590
1600
|
this.instanceId = deps.instanceId ?? globalThis.crypto.randomUUID();
|
|
1601
|
+
this.namespace = deps.namespace ?? "default";
|
|
1591
1602
|
this.leaseMs = deps.leaseMs ?? 3e4;
|
|
1592
1603
|
this.maxRecoveryAttempts = deps.maxRecoveryAttempts;
|
|
1593
1604
|
this.remoteAdvanceSilenceMs = deps.remoteAdvanceSilenceMs;
|
|
@@ -1908,6 +1919,7 @@ var WorkflowEngine = class {
|
|
|
1908
1919
|
workflow: name,
|
|
1909
1920
|
workflowVersion: registered.version,
|
|
1910
1921
|
status: "pending",
|
|
1922
|
+
namespace: this.namespace,
|
|
1911
1923
|
input,
|
|
1912
1924
|
tags,
|
|
1913
1925
|
searchAttributes: opts?.searchAttributes,
|
|
@@ -1944,6 +1956,10 @@ var WorkflowEngine = class {
|
|
|
1944
1956
|
error: run.error
|
|
1945
1957
|
};
|
|
1946
1958
|
}
|
|
1959
|
+
if (run.namespace !== void 0 && run.namespace !== this.namespace) {
|
|
1960
|
+
await this.store.releaseRunLock(runId);
|
|
1961
|
+
throw new NamespaceMismatch();
|
|
1962
|
+
}
|
|
1947
1963
|
const registered = this.workflows.get(versionKey(run.workflow, run.workflowVersion)) ?? await this.findInheritedRegistration(run);
|
|
1948
1964
|
if (!registered) {
|
|
1949
1965
|
throw new Error(`workflow ${run.workflow}@${run.workflowVersion} is not registered \u2014 keep the prior version deployed so in-flight runs can drain (skew protection)`);
|
|
@@ -2062,11 +2078,13 @@ var WorkflowEngine = class {
|
|
|
2062
2078
|
const inflight = [
|
|
2063
2079
|
...await this.store.listRuns({
|
|
2064
2080
|
workflow: reg.name,
|
|
2065
|
-
status: "running"
|
|
2081
|
+
status: "running",
|
|
2082
|
+
namespace: this.namespace
|
|
2066
2083
|
}),
|
|
2067
2084
|
...await this.store.listRuns({
|
|
2068
2085
|
workflow: reg.name,
|
|
2069
|
-
status: "suspended"
|
|
2086
|
+
status: "suspended",
|
|
2087
|
+
namespace: this.namespace
|
|
2070
2088
|
})
|
|
2071
2089
|
];
|
|
2072
2090
|
for (const run of inflight) {
|
|
@@ -2096,7 +2114,7 @@ var WorkflowEngine = class {
|
|
|
2096
2114
|
async recoverIncomplete(nowMs = this.clock()) {
|
|
2097
2115
|
if (this.draining) return [];
|
|
2098
2116
|
const results = [];
|
|
2099
|
-
for (const run of await this.store.listIncompleteRuns()) {
|
|
2117
|
+
for (const run of await this.store.listIncompleteRuns(this.namespace)) {
|
|
2100
2118
|
const acquired = await this.store.tryLockRun(run.id, this.instanceId, nowMs + this.leaseMs, nowMs);
|
|
2101
2119
|
if (!acquired) continue;
|
|
2102
2120
|
const settled = await this.countRecovery(run);
|
|
@@ -2166,7 +2184,7 @@ var WorkflowEngine = class {
|
|
|
2166
2184
|
* boot. A run still not due re-suspends cheaply without running new work.
|
|
2167
2185
|
*/
|
|
2168
2186
|
async resumeDueTimers(nowMs = this.clock()) {
|
|
2169
|
-
return this.resumeLeased(await this.store.listDueTimers(nowMs), nowMs);
|
|
2187
|
+
return this.resumeLeased(await this.store.listDueTimers(nowMs, this.namespace), nowMs);
|
|
2170
2188
|
}
|
|
2171
2189
|
/**
|
|
2172
2190
|
* Lease and execute one run by id — the worker side of dispatch. Acquires the recovery lease (so
|
|
@@ -2179,7 +2197,10 @@ var WorkflowEngine = class {
|
|
|
2179
2197
|
const nowMs = this.clock();
|
|
2180
2198
|
const acquired = await this.store.tryLockRun(runId, this.instanceId, nowMs + this.leaseMs, nowMs);
|
|
2181
2199
|
if (!acquired) return null;
|
|
2182
|
-
return this.resume(runId)
|
|
2200
|
+
return this.resume(runId).catch((err) => {
|
|
2201
|
+
if (err instanceof NamespaceMismatch) return null;
|
|
2202
|
+
throw err;
|
|
2203
|
+
});
|
|
2183
2204
|
}
|
|
2184
2205
|
/**
|
|
2185
2206
|
* Re-enqueue a run for a worker to (re-)execute — the dispatch-model **retry**. Sets it back to
|
|
@@ -2225,7 +2246,7 @@ var WorkflowEngine = class {
|
|
|
2225
2246
|
* {@link resumeDueTimers}.
|
|
2226
2247
|
*/
|
|
2227
2248
|
async runPending(nowMs = this.clock()) {
|
|
2228
|
-
return this.resumeLeased(await this.store.listPendingRuns(100), nowMs);
|
|
2249
|
+
return this.resumeLeased(await this.store.listPendingRuns(100, this.namespace), nowMs);
|
|
2229
2250
|
}
|
|
2230
2251
|
/**
|
|
2231
2252
|
* Resolve once `runId` reaches a settled state — terminal (completed/failed/cancelled/dead) or
|
|
@@ -2335,9 +2356,17 @@ var WorkflowEngine = class {
|
|
|
2335
2356
|
seq: waiter.seq,
|
|
2336
2357
|
name: `signal:${token}`,
|
|
2337
2358
|
kind: "signal",
|
|
2338
|
-
output: payload
|
|
2359
|
+
output: payload,
|
|
2360
|
+
// Carry the awaiting command's fan group (set when a `ctx.gather_children`/`ctx.all` fan-out
|
|
2361
|
+
// registered this waiter) onto the resolving `signal:child:<id>` checkpoint, so the dashboard
|
|
2362
|
+
// groups the child fan-out vertically instead of rendering it as a sequential chain. Undefined
|
|
2363
|
+
// for an ordinary (non-fan) signal/child await.
|
|
2364
|
+
parallelGroup: waiter.parallelGroup
|
|
2339
2365
|
}));
|
|
2340
|
-
return this.resume(waiter.runId)
|
|
2366
|
+
return this.resume(waiter.runId).catch((err) => {
|
|
2367
|
+
if (err instanceof NamespaceMismatch) return null;
|
|
2368
|
+
throw err;
|
|
2369
|
+
});
|
|
2341
2370
|
}
|
|
2342
2371
|
/**
|
|
2343
2372
|
* Ensure a run exists for `runId`, then deliver a signal to it — atomically race-free thanks to
|
|
@@ -3102,7 +3131,12 @@ var WorkflowEngine = class {
|
|
|
3102
3131
|
await this.store.putSignalWaiter({
|
|
3103
3132
|
token: `child:${childId}`,
|
|
3104
3133
|
runId: run.id,
|
|
3105
|
-
seq: cmd.seq
|
|
3134
|
+
seq: cmd.seq,
|
|
3135
|
+
// A `ctx.gather_children`/`ctx.all` fan-out stamps every `startChild` in the fan with the same
|
|
3136
|
+
// group. Thread it onto the waiter so the child's terminal `signal:child:<id>` checkpoint
|
|
3137
|
+
// (written by engine.signal when the child notifies the parent) carries the group and the
|
|
3138
|
+
// dashboard renders the fan as one parallel group. Undefined for a lone (non-fan) child.
|
|
3139
|
+
parallelGroup: cmd.parallelGroup
|
|
3106
3140
|
});
|
|
3107
3141
|
if (!await this.store.getRun(childId)) {
|
|
3108
3142
|
queueMicrotask(() => void this.start(cmd.workflow, cmd.input, childId).catch(() => void 0));
|
|
@@ -3491,7 +3525,10 @@ var WorkflowEngine = class {
|
|
|
3491
3525
|
queueMs: startedAt.getTime() - cp.enqueuedAt.getTime(),
|
|
3492
3526
|
durationMs: finishedAt.getTime() - startedAt.getTime()
|
|
3493
3527
|
});
|
|
3494
|
-
await this.resume(result.runId)
|
|
3528
|
+
await this.resume(result.runId).catch((err) => {
|
|
3529
|
+
if (err instanceof NamespaceMismatch) return null;
|
|
3530
|
+
throw err;
|
|
3531
|
+
});
|
|
3495
3532
|
}
|
|
3496
3533
|
/**
|
|
3497
3534
|
* A slot freed on `queue` (a fleet-wide signal): resume this instance's runs blocked on it so they
|
|
@@ -3789,14 +3826,14 @@ var CodecStateStore = class {
|
|
|
3789
3826
|
saveCheckpoint: /* @__PURE__ */ __name((cp) => tx.saveCheckpoint(this.encCp(cp)), "saveCheckpoint")
|
|
3790
3827
|
}));
|
|
3791
3828
|
}
|
|
3792
|
-
async listIncompleteRuns() {
|
|
3793
|
-
return (await this.inner.listIncompleteRuns()).map((r) => this.decRun(r));
|
|
3829
|
+
async listIncompleteRuns(namespace) {
|
|
3830
|
+
return (await this.inner.listIncompleteRuns(namespace)).map((r) => this.decRun(r));
|
|
3794
3831
|
}
|
|
3795
|
-
async listPendingRuns(limit) {
|
|
3796
|
-
return (await this.inner.listPendingRuns(limit)).map((r) => this.decRun(r));
|
|
3832
|
+
async listPendingRuns(limit, namespace) {
|
|
3833
|
+
return (await this.inner.listPendingRuns(limit, namespace)).map((r) => this.decRun(r));
|
|
3797
3834
|
}
|
|
3798
|
-
async listDueTimers(nowMs) {
|
|
3799
|
-
return (await this.inner.listDueTimers(nowMs)).map((r) => this.decRun(r));
|
|
3835
|
+
async listDueTimers(nowMs, namespace) {
|
|
3836
|
+
return (await this.inner.listDueTimers(nowMs, namespace)).map((r) => this.decRun(r));
|
|
3800
3837
|
}
|
|
3801
3838
|
tryLockRun(runId, owner, leaseUntilMs, nowMs) {
|
|
3802
3839
|
return this.inner.tryLockRun(runId, owner, leaseUntilMs, nowMs);
|
|
@@ -4151,7 +4188,8 @@ var InMemoryStateStore = class {
|
|
|
4151
4188
|
}
|
|
4152
4189
|
async createRun(run) {
|
|
4153
4190
|
this.runs.set(run.id, {
|
|
4154
|
-
...run
|
|
4191
|
+
...run,
|
|
4192
|
+
namespace: run.namespace ?? "default"
|
|
4155
4193
|
});
|
|
4156
4194
|
this.reindexAttributes(run.id, run.searchAttributes);
|
|
4157
4195
|
}
|
|
@@ -4192,24 +4230,24 @@ var InMemoryStateStore = class {
|
|
|
4192
4230
|
...checkpoint
|
|
4193
4231
|
});
|
|
4194
4232
|
}
|
|
4195
|
-
async listIncompleteRuns() {
|
|
4233
|
+
async listIncompleteRuns(namespace) {
|
|
4196
4234
|
return [
|
|
4197
4235
|
...this.runs.values()
|
|
4198
|
-
].filter((r) => r.status === "running" || r.status === "cancelling").map((r) => ({
|
|
4236
|
+
].filter((r) => (r.status === "running" || r.status === "cancelling") && (namespace === void 0 || r.namespace === namespace)).map((r) => ({
|
|
4199
4237
|
...r
|
|
4200
4238
|
}));
|
|
4201
4239
|
}
|
|
4202
|
-
async listPendingRuns(limit) {
|
|
4240
|
+
async listPendingRuns(limit, namespace) {
|
|
4203
4241
|
return [
|
|
4204
4242
|
...this.runs.values()
|
|
4205
|
-
].filter((r) => r.status === "pending").sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime() || a.id.localeCompare(b.id)).slice(0, limit).map((r) => ({
|
|
4243
|
+
].filter((r) => r.status === "pending" && (namespace === void 0 || r.namespace === namespace)).sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime() || a.id.localeCompare(b.id)).slice(0, limit).map((r) => ({
|
|
4206
4244
|
...r
|
|
4207
4245
|
}));
|
|
4208
4246
|
}
|
|
4209
|
-
async listDueTimers(nowMs) {
|
|
4247
|
+
async listDueTimers(nowMs, namespace) {
|
|
4210
4248
|
return [
|
|
4211
4249
|
...this.runs.values()
|
|
4212
|
-
].filter((r) => r.status === "suspended" && r.wakeAt !== void 0 && r.wakeAt <= nowMs).map((r) => ({
|
|
4250
|
+
].filter((r) => r.status === "suspended" && r.wakeAt !== void 0 && r.wakeAt <= nowMs && (namespace === void 0 || r.namespace === namespace)).map((r) => ({
|
|
4213
4251
|
...r
|
|
4214
4252
|
}));
|
|
4215
4253
|
}
|
|
@@ -4324,6 +4362,7 @@ var InMemoryStateStore = class {
|
|
|
4324
4362
|
if (query.status) runs = runs.filter((r) => r.status === query.status);
|
|
4325
4363
|
if (query.statuses) runs = runs.filter((r) => query.statuses?.includes(r.status));
|
|
4326
4364
|
if (query.tag) runs = runs.filter((r) => r.tags?.includes(query.tag));
|
|
4365
|
+
if (query.namespace !== void 0) runs = runs.filter((r) => r.namespace === query.namespace);
|
|
4327
4366
|
if (query.attributes?.length) {
|
|
4328
4367
|
let candidates = null;
|
|
4329
4368
|
for (const f of query.attributes) {
|