@dudousxd/nestjs-durable-core 0.38.0 → 0.40.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 +165 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +94 -9
- package/dist/index.d.ts +94 -9
- package/dist/index.js +165 -25
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1440,6 +1440,14 @@ function isNewerVersion(a, b) {
|
|
|
1440
1440
|
}) > 0;
|
|
1441
1441
|
}
|
|
1442
1442
|
__name(isNewerVersion, "isNewerVersion");
|
|
1443
|
+
var NamespaceMismatch = class NamespaceMismatch2 extends Error {
|
|
1444
|
+
static {
|
|
1445
|
+
__name(this, "NamespaceMismatch");
|
|
1446
|
+
}
|
|
1447
|
+
constructor() {
|
|
1448
|
+
super("namespace-mismatch");
|
|
1449
|
+
}
|
|
1450
|
+
};
|
|
1443
1451
|
var WorkflowEngine = class {
|
|
1444
1452
|
static {
|
|
1445
1453
|
__name(this, "WorkflowEngine");
|
|
@@ -1450,6 +1458,7 @@ var WorkflowEngine = class {
|
|
|
1450
1458
|
controlPlane;
|
|
1451
1459
|
clock;
|
|
1452
1460
|
instanceId;
|
|
1461
|
+
namespace;
|
|
1453
1462
|
leaseMs;
|
|
1454
1463
|
maxRecoveryAttempts;
|
|
1455
1464
|
remoteAdvanceSilenceMs;
|
|
@@ -1516,6 +1525,7 @@ var WorkflowEngine = class {
|
|
|
1516
1525
|
this.admission = deps.admission ?? new InMemoryAdmissionBackend(this.clock);
|
|
1517
1526
|
this.admission.onFreed?.((queue) => this.wakeQueueWaiters(queue));
|
|
1518
1527
|
this.instanceId = deps.instanceId ?? globalThis.crypto.randomUUID();
|
|
1528
|
+
this.namespace = deps.namespace ?? "default";
|
|
1519
1529
|
this.leaseMs = deps.leaseMs ?? 3e4;
|
|
1520
1530
|
this.maxRecoveryAttempts = deps.maxRecoveryAttempts;
|
|
1521
1531
|
this.remoteAdvanceSilenceMs = deps.remoteAdvanceSilenceMs;
|
|
@@ -1626,8 +1636,21 @@ var WorkflowEngine = class {
|
|
|
1626
1636
|
* Register a workflow version. Register multiple versions of the same name to keep in-flight
|
|
1627
1637
|
* runs working across a breaking change: old runs resume on the version they started on, new
|
|
1628
1638
|
* runs start on the newest registered version.
|
|
1639
|
+
*
|
|
1640
|
+
* GROUP-SERVED (uniform dispatch, opt-in): pass `{ group, executor }` to have the engine DISPATCH
|
|
1641
|
+
* this workflow's turns to a worker `group` (via `executor.advance`) instead of running `fn`
|
|
1642
|
+
* inline — exactly as {@link registerRemote} does for a cross-SDK (e.g. Python) body, EXCEPT the
|
|
1643
|
+
* body is a TS `fn` the engine retains so an IN-APP worker on `group` can fetch it by name
|
|
1644
|
+
* ({@link workflowBody}) and run it. This is "one app, both roles": the same process owns the
|
|
1645
|
+
* engine AND consumes its own group. Recovery, timers, singleton, cancel and dead-lettering stay
|
|
1646
|
+
* engine concerns, identical to a remote run. OMIT `group`/`executor` (the default) to keep the
|
|
1647
|
+
* inline fast path — `fn` runs in-process and the run pays zero dispatch round-trips. The first
|
|
1648
|
+
* step toward routing every run through a group with no local/remote flag (Phase 3).
|
|
1629
1649
|
*/
|
|
1630
1650
|
register(name, version, fn, opts) {
|
|
1651
|
+
if (opts?.group == null !== (opts?.executor == null)) {
|
|
1652
|
+
throw new Error(`workflow ${name}@${version}: register({ group, executor }) needs BOTH group and executor (or neither)`);
|
|
1653
|
+
}
|
|
1631
1654
|
const registered = {
|
|
1632
1655
|
name,
|
|
1633
1656
|
version,
|
|
@@ -1637,8 +1660,17 @@ var WorkflowEngine = class {
|
|
|
1637
1660
|
executionTimeoutMs: opts?.executionTimeout != null ? parseDuration(opts.executionTimeout) : void 0,
|
|
1638
1661
|
validateInput: opts?.validateInput,
|
|
1639
1662
|
onEvent: opts?.onEvent,
|
|
1640
|
-
eventBatch: opts?.eventBatch
|
|
1663
|
+
eventBatch: opts?.eventBatch,
|
|
1664
|
+
// A real, retained in-process body — so `workflowBody` can hand it to an in-app worker, and so
|
|
1665
|
+
// it is NOT confused with the throwing stub `registerRemote` installs for a body-less remote.
|
|
1666
|
+
hasBody: true
|
|
1641
1667
|
};
|
|
1668
|
+
if (opts?.group != null && opts?.executor != null) {
|
|
1669
|
+
registered.remote = {
|
|
1670
|
+
group: opts.group,
|
|
1671
|
+
executor: opts.executor
|
|
1672
|
+
};
|
|
1673
|
+
}
|
|
1642
1674
|
this.workflows.set(versionKey(name, version), registered);
|
|
1643
1675
|
const current = this.latest.get(name);
|
|
1644
1676
|
if (!current || isNewerVersion(version, current.version)) this.latest.set(name, registered);
|
|
@@ -1649,6 +1681,17 @@ var WorkflowEngine = class {
|
|
|
1649
1681
|
}
|
|
1650
1682
|
}
|
|
1651
1683
|
/**
|
|
1684
|
+
* The retained in-process body for `name@version`, for an IN-APP worker that consumes this engine's
|
|
1685
|
+
* own group to SERVE a group-served `register(..., { group, executor })` workflow (uniform dispatch):
|
|
1686
|
+
* the worker fetches the body by name when it picks up the dispatched {@link WorkflowTask}, replays
|
|
1687
|
+
* it, and returns the {@link WorkflowDecision}. `undefined` for an unregistered name or a body-less
|
|
1688
|
+
* remote (a `registerRemote` / synthesized child carries only a throwing stub, never handed out).
|
|
1689
|
+
*/
|
|
1690
|
+
workflowBody(name, version) {
|
|
1691
|
+
const reg = this.workflows.get(versionKey(name, version));
|
|
1692
|
+
return reg?.hasBody ? reg.fn : void 0;
|
|
1693
|
+
}
|
|
1694
|
+
/**
|
|
1652
1695
|
* Register a workflow whose body runs in another SDK (e.g. Python). The engine owns the run exactly
|
|
1653
1696
|
* as for a TS workflow — it persists checkpoints, recovers, runs timers — but advances it by handing
|
|
1654
1697
|
* the run's history to `executor` (which dispatches a {@link WorkflowTask} to the worker) and applying
|
|
@@ -1774,7 +1817,11 @@ var WorkflowEngine = class {
|
|
|
1774
1817
|
}
|
|
1775
1818
|
async start(workflow, input, runId, opts) {
|
|
1776
1819
|
const name = workflowName(workflow);
|
|
1777
|
-
|
|
1820
|
+
let registered = this.latest.get(name);
|
|
1821
|
+
if (!registered) {
|
|
1822
|
+
const ancestor = await this.findRemoteAncestor(runId);
|
|
1823
|
+
if (ancestor) registered = this.synthesizeRemoteChild(name, ancestor.version, ancestor);
|
|
1824
|
+
}
|
|
1778
1825
|
if (!registered) throw new Error(`workflow ${name} is not registered`);
|
|
1779
1826
|
await registered.validateInput?.(input);
|
|
1780
1827
|
const prior = await this.store.getRun(runId);
|
|
@@ -1799,6 +1846,7 @@ var WorkflowEngine = class {
|
|
|
1799
1846
|
workflow: name,
|
|
1800
1847
|
workflowVersion: registered.version,
|
|
1801
1848
|
status: "pending",
|
|
1849
|
+
namespace: this.namespace,
|
|
1802
1850
|
input,
|
|
1803
1851
|
tags,
|
|
1804
1852
|
searchAttributes: opts?.searchAttributes,
|
|
@@ -1835,12 +1883,91 @@ var WorkflowEngine = class {
|
|
|
1835
1883
|
error: run.error
|
|
1836
1884
|
};
|
|
1837
1885
|
}
|
|
1838
|
-
|
|
1886
|
+
if (run.namespace !== void 0 && run.namespace !== this.namespace) {
|
|
1887
|
+
await this.store.releaseRunLock(runId);
|
|
1888
|
+
throw new NamespaceMismatch();
|
|
1889
|
+
}
|
|
1890
|
+
const registered = this.workflows.get(versionKey(run.workflow, run.workflowVersion)) ?? await this.findInheritedRegistration(run);
|
|
1839
1891
|
if (!registered) {
|
|
1840
1892
|
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)`);
|
|
1841
1893
|
}
|
|
1842
1894
|
return this.track(this.execute(run, registered.fn));
|
|
1843
1895
|
}
|
|
1896
|
+
/**
|
|
1897
|
+
* The registration for an UNREGISTERED run, INHERITED from its nearest REMOTE ancestor — or
|
|
1898
|
+
* `undefined` if it has none (the skew-protection error case in {@link resume}). Callers check the
|
|
1899
|
+
* flat registry FIRST (so an explicit `registerRemote(name, …)` ALWAYS wins, and a registered run
|
|
1900
|
+
* never reaches here); this resolves only the new case: a child spawned by a remote workflow (e.g. a
|
|
1901
|
+
* Python `gather_children` / `start_child` fan-out) of a name the host never `registerRemote`-ed. It
|
|
1902
|
+
* is driven as a remote run on the ancestor's group + the SAME executor instance, so the host needs
|
|
1903
|
+
* no redundant registration per child name.
|
|
1904
|
+
*
|
|
1905
|
+
* RECOMPUTED per resume rather than memoized into `this.workflows`: a synthesized child is not a real
|
|
1906
|
+
* registration and must not leak into `latest`, `knownGroups`, or `sweepTimeouts` (which iterate the
|
|
1907
|
+
* registry); recomputing also stays correct if the ancestor's remote registration is re-pointed at a
|
|
1908
|
+
* new executor across a deploy. Only unregistered runs pay it, so registered workflows pay nothing.
|
|
1909
|
+
*/
|
|
1910
|
+
async findInheritedRegistration(run) {
|
|
1911
|
+
const ancestor = await this.findRemoteAncestor(run.id);
|
|
1912
|
+
if (!ancestor) return void 0;
|
|
1913
|
+
return this.synthesizeRemoteChild(run.workflow, run.workflowVersion, ancestor);
|
|
1914
|
+
}
|
|
1915
|
+
/**
|
|
1916
|
+
* A throwaway {@link RegisteredWorkflow} that routes `name@version` as a remote run on the ancestor's
|
|
1917
|
+
* group via the ancestor's SAME executor instance. The executor is group-scoped (it dispatches a
|
|
1918
|
+
* {@link WorkflowTask} carrying `run.workflow`, and the worker picks the body by name), so reusing it
|
|
1919
|
+
* is correct AND required — a second executor on the same group would race the worker for results.
|
|
1920
|
+
* Only `remote` is inherited; the child gets none of the ancestor's singleton/timeout/validator, so
|
|
1921
|
+
* its identity stays its own.
|
|
1922
|
+
*/
|
|
1923
|
+
synthesizeRemoteChild(name, version, ancestor) {
|
|
1924
|
+
const remote = ancestor.remote;
|
|
1925
|
+
if (!remote) throw new Error(`workflow ${ancestor.name} is not a remote workflow`);
|
|
1926
|
+
return {
|
|
1927
|
+
name,
|
|
1928
|
+
version,
|
|
1929
|
+
fn: /* @__PURE__ */ __name(() => {
|
|
1930
|
+
throw new Error(`workflow ${name} is remote \u2014 it has no in-process body`);
|
|
1931
|
+
}, "fn"),
|
|
1932
|
+
remote
|
|
1933
|
+
};
|
|
1934
|
+
}
|
|
1935
|
+
/**
|
|
1936
|
+
* Walk the parent chain of `childRunId` to the nearest ancestor registered as REMOTE, returning its
|
|
1937
|
+
* registration (or `undefined` if there is none). The parent of an awaited child is found via its
|
|
1938
|
+
* live `child:<childId>` signal waiter — present for as long as the parent is suspended awaiting the
|
|
1939
|
+
* child, i.e. throughout the child's executable lifetime (start, every resume, crash recovery, cancel
|
|
1940
|
+
* cascade), which is exactly when we resolve. A registered-but-LOCAL parent stops the walk (an
|
|
1941
|
+
* unregistered child of a TS workflow is a genuine misconfiguration → skew error); only an
|
|
1942
|
+
* unregistered parent keeps walking, so a child of an inherited child still reaches the remote root.
|
|
1943
|
+
* `visited` guards against a pathological cyclic id graph.
|
|
1944
|
+
*/
|
|
1945
|
+
async findRemoteAncestor(childRunId, visited = /* @__PURE__ */ new Set()) {
|
|
1946
|
+
if (visited.has(childRunId)) return void 0;
|
|
1947
|
+
visited.add(childRunId);
|
|
1948
|
+
const parentRunId = await this.findParentRunId(childRunId);
|
|
1949
|
+
if (!parentRunId) return void 0;
|
|
1950
|
+
const parent = await this.store.getRun(parentRunId);
|
|
1951
|
+
if (!parent) return void 0;
|
|
1952
|
+
const parentReg = this.workflows.get(versionKey(parent.workflow, parent.workflowVersion));
|
|
1953
|
+
if (parentReg?.remote) return parentReg;
|
|
1954
|
+
if (parentReg) return void 0;
|
|
1955
|
+
return this.findRemoteAncestor(parent.id, visited);
|
|
1956
|
+
}
|
|
1957
|
+
/**
|
|
1958
|
+
* The run that spawned `childRunId`, via its live `child:<childRunId>` signal waiter — every awaited
|
|
1959
|
+
* child (`ctx.child`, `ctx.all`, a remote `start_child`) suspends its parent on exactly this waiter,
|
|
1960
|
+
* and the waiter is written BEFORE the child is started. Only reached for an UNREGISTERED child, so
|
|
1961
|
+
* registered runs never pay the scan; returns `undefined` once the parent has settled the child (the
|
|
1962
|
+
* waiter is consumed), but by then the child is terminal and no longer resolved.
|
|
1963
|
+
*/
|
|
1964
|
+
async findParentRunId(childRunId) {
|
|
1965
|
+
const token = `child:${childRunId}`;
|
|
1966
|
+
for (const waiter of await this.store.listSignalWaiters("child:")) {
|
|
1967
|
+
if (waiter.token === token) return waiter.runId;
|
|
1968
|
+
}
|
|
1969
|
+
return void 0;
|
|
1970
|
+
}
|
|
1844
1971
|
/** Track an in-flight execution so {@link drain} can wait for it. */
|
|
1845
1972
|
track(p) {
|
|
1846
1973
|
this.inflight.add(p);
|
|
@@ -1878,11 +2005,13 @@ var WorkflowEngine = class {
|
|
|
1878
2005
|
const inflight = [
|
|
1879
2006
|
...await this.store.listRuns({
|
|
1880
2007
|
workflow: reg.name,
|
|
1881
|
-
status: "running"
|
|
2008
|
+
status: "running",
|
|
2009
|
+
namespace: this.namespace
|
|
1882
2010
|
}),
|
|
1883
2011
|
...await this.store.listRuns({
|
|
1884
2012
|
workflow: reg.name,
|
|
1885
|
-
status: "suspended"
|
|
2013
|
+
status: "suspended",
|
|
2014
|
+
namespace: this.namespace
|
|
1886
2015
|
})
|
|
1887
2016
|
];
|
|
1888
2017
|
for (const run of inflight) {
|
|
@@ -1912,7 +2041,7 @@ var WorkflowEngine = class {
|
|
|
1912
2041
|
async recoverIncomplete(nowMs = this.clock()) {
|
|
1913
2042
|
if (this.draining) return [];
|
|
1914
2043
|
const results = [];
|
|
1915
|
-
for (const run of await this.store.listIncompleteRuns()) {
|
|
2044
|
+
for (const run of await this.store.listIncompleteRuns(this.namespace)) {
|
|
1916
2045
|
const acquired = await this.store.tryLockRun(run.id, this.instanceId, nowMs + this.leaseMs, nowMs);
|
|
1917
2046
|
if (!acquired) continue;
|
|
1918
2047
|
const settled = await this.countRecovery(run);
|
|
@@ -1982,7 +2111,7 @@ var WorkflowEngine = class {
|
|
|
1982
2111
|
* boot. A run still not due re-suspends cheaply without running new work.
|
|
1983
2112
|
*/
|
|
1984
2113
|
async resumeDueTimers(nowMs = this.clock()) {
|
|
1985
|
-
return this.resumeLeased(await this.store.listDueTimers(nowMs), nowMs);
|
|
2114
|
+
return this.resumeLeased(await this.store.listDueTimers(nowMs, this.namespace), nowMs);
|
|
1986
2115
|
}
|
|
1987
2116
|
/**
|
|
1988
2117
|
* Lease and execute one run by id — the worker side of dispatch. Acquires the recovery lease (so
|
|
@@ -1995,7 +2124,10 @@ var WorkflowEngine = class {
|
|
|
1995
2124
|
const nowMs = this.clock();
|
|
1996
2125
|
const acquired = await this.store.tryLockRun(runId, this.instanceId, nowMs + this.leaseMs, nowMs);
|
|
1997
2126
|
if (!acquired) return null;
|
|
1998
|
-
return this.resume(runId)
|
|
2127
|
+
return this.resume(runId).catch((err) => {
|
|
2128
|
+
if (err instanceof NamespaceMismatch) return null;
|
|
2129
|
+
throw err;
|
|
2130
|
+
});
|
|
1999
2131
|
}
|
|
2000
2132
|
/**
|
|
2001
2133
|
* Re-enqueue a run for a worker to (re-)execute — the dispatch-model **retry**. Sets it back to
|
|
@@ -2041,7 +2173,7 @@ var WorkflowEngine = class {
|
|
|
2041
2173
|
* {@link resumeDueTimers}.
|
|
2042
2174
|
*/
|
|
2043
2175
|
async runPending(nowMs = this.clock()) {
|
|
2044
|
-
return this.resumeLeased(await this.store.listPendingRuns(100), nowMs);
|
|
2176
|
+
return this.resumeLeased(await this.store.listPendingRuns(100, this.namespace), nowMs);
|
|
2045
2177
|
}
|
|
2046
2178
|
/**
|
|
2047
2179
|
* Resolve once `runId` reaches a settled state — terminal (completed/failed/cancelled/dead) or
|
|
@@ -2153,7 +2285,10 @@ var WorkflowEngine = class {
|
|
|
2153
2285
|
kind: "signal",
|
|
2154
2286
|
output: payload
|
|
2155
2287
|
}));
|
|
2156
|
-
return this.resume(waiter.runId)
|
|
2288
|
+
return this.resume(waiter.runId).catch((err) => {
|
|
2289
|
+
if (err instanceof NamespaceMismatch) return null;
|
|
2290
|
+
throw err;
|
|
2291
|
+
});
|
|
2157
2292
|
}
|
|
2158
2293
|
/**
|
|
2159
2294
|
* Ensure a run exists for `runId`, then deliver a signal to it — atomically race-free thanks to
|
|
@@ -2530,7 +2665,7 @@ var WorkflowEngine = class {
|
|
|
2530
2665
|
});
|
|
2531
2666
|
}
|
|
2532
2667
|
async execute(run, fn) {
|
|
2533
|
-
const registered = this.workflows.get(versionKey(run.workflow, run.workflowVersion));
|
|
2668
|
+
const registered = this.workflows.get(versionKey(run.workflow, run.workflowVersion)) ?? await this.findInheritedRegistration(run);
|
|
2534
2669
|
const lockNow = this.clock();
|
|
2535
2670
|
if (run.lockedBy !== this.instanceId || (run.lockedUntil ?? 0) <= lockNow) {
|
|
2536
2671
|
if (!await this.store.tryLockRun(run.id, this.instanceId, lockNow + this.leaseMs, lockNow)) {
|
|
@@ -3307,7 +3442,10 @@ var WorkflowEngine = class {
|
|
|
3307
3442
|
queueMs: startedAt.getTime() - cp.enqueuedAt.getTime(),
|
|
3308
3443
|
durationMs: finishedAt.getTime() - startedAt.getTime()
|
|
3309
3444
|
});
|
|
3310
|
-
await this.resume(result.runId)
|
|
3445
|
+
await this.resume(result.runId).catch((err) => {
|
|
3446
|
+
if (err instanceof NamespaceMismatch) return null;
|
|
3447
|
+
throw err;
|
|
3448
|
+
});
|
|
3311
3449
|
}
|
|
3312
3450
|
/**
|
|
3313
3451
|
* A slot freed on `queue` (a fleet-wide signal): resume this instance's runs blocked on it so they
|
|
@@ -3605,14 +3743,14 @@ var CodecStateStore = class {
|
|
|
3605
3743
|
saveCheckpoint: /* @__PURE__ */ __name((cp) => tx.saveCheckpoint(this.encCp(cp)), "saveCheckpoint")
|
|
3606
3744
|
}));
|
|
3607
3745
|
}
|
|
3608
|
-
async listIncompleteRuns() {
|
|
3609
|
-
return (await this.inner.listIncompleteRuns()).map((r) => this.decRun(r));
|
|
3746
|
+
async listIncompleteRuns(namespace) {
|
|
3747
|
+
return (await this.inner.listIncompleteRuns(namespace)).map((r) => this.decRun(r));
|
|
3610
3748
|
}
|
|
3611
|
-
async listPendingRuns(limit) {
|
|
3612
|
-
return (await this.inner.listPendingRuns(limit)).map((r) => this.decRun(r));
|
|
3749
|
+
async listPendingRuns(limit, namespace) {
|
|
3750
|
+
return (await this.inner.listPendingRuns(limit, namespace)).map((r) => this.decRun(r));
|
|
3613
3751
|
}
|
|
3614
|
-
async listDueTimers(nowMs) {
|
|
3615
|
-
return (await this.inner.listDueTimers(nowMs)).map((r) => this.decRun(r));
|
|
3752
|
+
async listDueTimers(nowMs, namespace) {
|
|
3753
|
+
return (await this.inner.listDueTimers(nowMs, namespace)).map((r) => this.decRun(r));
|
|
3616
3754
|
}
|
|
3617
3755
|
tryLockRun(runId, owner, leaseUntilMs, nowMs) {
|
|
3618
3756
|
return this.inner.tryLockRun(runId, owner, leaseUntilMs, nowMs);
|
|
@@ -3967,7 +4105,8 @@ var InMemoryStateStore = class {
|
|
|
3967
4105
|
}
|
|
3968
4106
|
async createRun(run) {
|
|
3969
4107
|
this.runs.set(run.id, {
|
|
3970
|
-
...run
|
|
4108
|
+
...run,
|
|
4109
|
+
namespace: run.namespace ?? "default"
|
|
3971
4110
|
});
|
|
3972
4111
|
this.reindexAttributes(run.id, run.searchAttributes);
|
|
3973
4112
|
}
|
|
@@ -4008,24 +4147,24 @@ var InMemoryStateStore = class {
|
|
|
4008
4147
|
...checkpoint
|
|
4009
4148
|
});
|
|
4010
4149
|
}
|
|
4011
|
-
async listIncompleteRuns() {
|
|
4150
|
+
async listIncompleteRuns(namespace) {
|
|
4012
4151
|
return [
|
|
4013
4152
|
...this.runs.values()
|
|
4014
|
-
].filter((r) => r.status === "running" || r.status === "cancelling").map((r) => ({
|
|
4153
|
+
].filter((r) => (r.status === "running" || r.status === "cancelling") && (namespace === void 0 || r.namespace === namespace)).map((r) => ({
|
|
4015
4154
|
...r
|
|
4016
4155
|
}));
|
|
4017
4156
|
}
|
|
4018
|
-
async listPendingRuns(limit) {
|
|
4157
|
+
async listPendingRuns(limit, namespace) {
|
|
4019
4158
|
return [
|
|
4020
4159
|
...this.runs.values()
|
|
4021
|
-
].filter((r) => r.status === "pending").sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime() || a.id.localeCompare(b.id)).slice(0, limit).map((r) => ({
|
|
4160
|
+
].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) => ({
|
|
4022
4161
|
...r
|
|
4023
4162
|
}));
|
|
4024
4163
|
}
|
|
4025
|
-
async listDueTimers(nowMs) {
|
|
4164
|
+
async listDueTimers(nowMs, namespace) {
|
|
4026
4165
|
return [
|
|
4027
4166
|
...this.runs.values()
|
|
4028
|
-
].filter((r) => r.status === "suspended" && r.wakeAt !== void 0 && r.wakeAt <= nowMs).map((r) => ({
|
|
4167
|
+
].filter((r) => r.status === "suspended" && r.wakeAt !== void 0 && r.wakeAt <= nowMs && (namespace === void 0 || r.namespace === namespace)).map((r) => ({
|
|
4029
4168
|
...r
|
|
4030
4169
|
}));
|
|
4031
4170
|
}
|
|
@@ -4140,6 +4279,7 @@ var InMemoryStateStore = class {
|
|
|
4140
4279
|
if (query.status) runs = runs.filter((r) => r.status === query.status);
|
|
4141
4280
|
if (query.statuses) runs = runs.filter((r) => query.statuses?.includes(r.status));
|
|
4142
4281
|
if (query.tag) runs = runs.filter((r) => r.tags?.includes(query.tag));
|
|
4282
|
+
if (query.namespace !== void 0) runs = runs.filter((r) => r.namespace === query.namespace);
|
|
4143
4283
|
if (query.attributes?.length) {
|
|
4144
4284
|
let candidates = null;
|
|
4145
4285
|
for (const f of query.attributes) {
|