@dudousxd/nestjs-durable-core 0.64.0 → 0.65.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 +270 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +424 -137
- package/dist/index.d.ts +424 -137
- package/dist/index.js +267 -11
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -981,6 +981,9 @@ function normalizeDescriptor(raw) {
|
|
|
981
981
|
],
|
|
982
982
|
workflows: raw.workflows ?? [],
|
|
983
983
|
steps: raw.steps ?? [],
|
|
984
|
+
...raw.registrations !== void 0 ? {
|
|
985
|
+
registrations: raw.registrations
|
|
986
|
+
} : {},
|
|
984
987
|
...raw.partition !== void 0 ? {
|
|
985
988
|
partition: raw.partition
|
|
986
989
|
} : {},
|
|
@@ -991,6 +994,23 @@ function normalizeDescriptor(raw) {
|
|
|
991
994
|
};
|
|
992
995
|
}
|
|
993
996
|
__name(normalizeDescriptor, "normalizeDescriptor");
|
|
997
|
+
function canonicalizeRegistrations(regs) {
|
|
998
|
+
const canonical = regs.map((r) => ({
|
|
999
|
+
name: r.name,
|
|
1000
|
+
version: r.version ?? null,
|
|
1001
|
+
group: r.group ?? null,
|
|
1002
|
+
requires: r.requires ? [
|
|
1003
|
+
...new Set(r.requires)
|
|
1004
|
+
].sort() : null,
|
|
1005
|
+
origin: r.origin ?? null
|
|
1006
|
+
}));
|
|
1007
|
+
const byJson = /* @__PURE__ */ new Map();
|
|
1008
|
+
for (const entry of canonical) byJson.set(JSON.stringify(entry), entry);
|
|
1009
|
+
return [
|
|
1010
|
+
...byJson.keys()
|
|
1011
|
+
].sort().map((k) => byJson.get(k));
|
|
1012
|
+
}
|
|
1013
|
+
__name(canonicalizeRegistrations, "canonicalizeRegistrations");
|
|
994
1014
|
function canonicalizeForHash(d) {
|
|
995
1015
|
const set = /* @__PURE__ */ __name((xs) => [
|
|
996
1016
|
...new Set(xs)
|
|
@@ -1012,6 +1032,9 @@ function canonicalizeForHash(d) {
|
|
|
1012
1032
|
capabilities: set(d.capabilities),
|
|
1013
1033
|
workflows: set(d.workflows),
|
|
1014
1034
|
steps: set(d.steps),
|
|
1035
|
+
...d.registrations !== void 0 ? {
|
|
1036
|
+
registrations: canonicalizeRegistrations(d.registrations)
|
|
1037
|
+
} : {},
|
|
1015
1038
|
partition: d.partition ?? null,
|
|
1016
1039
|
namespace: d.namespace ?? null,
|
|
1017
1040
|
startedAt: d.startedAt
|
|
@@ -1044,6 +1067,144 @@ function heartbeatStatus(descriptor, opts = {}) {
|
|
|
1044
1067
|
};
|
|
1045
1068
|
}
|
|
1046
1069
|
__name(heartbeatStatus, "heartbeatStatus");
|
|
1070
|
+
function describeWorker(opts) {
|
|
1071
|
+
const version = CURRENT_PROTOCOL_VERSION;
|
|
1072
|
+
const registrations = [
|
|
1073
|
+
...opts.registrations ?? []
|
|
1074
|
+
].sort((a, b) => `${a.name}@${a.version ?? ""}`.localeCompare(`${b.name}@${b.version ?? ""}`));
|
|
1075
|
+
return {
|
|
1076
|
+
instanceId: opts.instanceId,
|
|
1077
|
+
runtime: opts.runtime,
|
|
1078
|
+
sdk: {
|
|
1079
|
+
name: opts.sdk.name,
|
|
1080
|
+
version: opts.sdk.version
|
|
1081
|
+
},
|
|
1082
|
+
protocol: {
|
|
1083
|
+
version,
|
|
1084
|
+
range: [
|
|
1085
|
+
version,
|
|
1086
|
+
version
|
|
1087
|
+
]
|
|
1088
|
+
},
|
|
1089
|
+
capabilities: [
|
|
1090
|
+
...LEGACY_V1_CAPABILITIES
|
|
1091
|
+
],
|
|
1092
|
+
workflows: [
|
|
1093
|
+
...opts.workflows ?? []
|
|
1094
|
+
].sort(),
|
|
1095
|
+
steps: [
|
|
1096
|
+
...opts.steps
|
|
1097
|
+
].sort(),
|
|
1098
|
+
...registrations.length > 0 ? {
|
|
1099
|
+
registrations
|
|
1100
|
+
} : {},
|
|
1101
|
+
...opts.partition ? {
|
|
1102
|
+
partition: opts.partition
|
|
1103
|
+
} : {},
|
|
1104
|
+
...opts.namespace && opts.namespace !== "default" ? {
|
|
1105
|
+
namespace: opts.namespace
|
|
1106
|
+
} : {},
|
|
1107
|
+
startedAt: opts.startedAt
|
|
1108
|
+
};
|
|
1109
|
+
}
|
|
1110
|
+
__name(describeWorker, "describeWorker");
|
|
1111
|
+
|
|
1112
|
+
// src/handshake/announced.ts
|
|
1113
|
+
function announcementsOf(raw) {
|
|
1114
|
+
const d = normalizeDescriptor(raw);
|
|
1115
|
+
const identity = {
|
|
1116
|
+
instanceId: d.instanceId,
|
|
1117
|
+
runtime: d.runtime
|
|
1118
|
+
};
|
|
1119
|
+
const announcements = (d.registrations ?? []).map((reg) => ({
|
|
1120
|
+
...reg,
|
|
1121
|
+
...identity
|
|
1122
|
+
}));
|
|
1123
|
+
const covered = new Set(announcements.map((a) => a.name));
|
|
1124
|
+
for (const name of d.workflows) {
|
|
1125
|
+
if (!covered.has(name)) announcements.push({
|
|
1126
|
+
name,
|
|
1127
|
+
...identity
|
|
1128
|
+
});
|
|
1129
|
+
}
|
|
1130
|
+
return announcements;
|
|
1131
|
+
}
|
|
1132
|
+
__name(announcementsOf, "announcementsOf");
|
|
1133
|
+
function announcementKey(a) {
|
|
1134
|
+
return a.version === void 0 ? a.name : `${a.name}@${a.version}`;
|
|
1135
|
+
}
|
|
1136
|
+
__name(announcementKey, "announcementKey");
|
|
1137
|
+
function stated(values) {
|
|
1138
|
+
return [
|
|
1139
|
+
...new Set(values.filter((v) => v !== void 0))
|
|
1140
|
+
].sort();
|
|
1141
|
+
}
|
|
1142
|
+
__name(stated, "stated");
|
|
1143
|
+
function aggregateAnnouncements(descriptors) {
|
|
1144
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
1145
|
+
for (const descriptor of descriptors) {
|
|
1146
|
+
for (const announcement of announcementsOf(descriptor)) {
|
|
1147
|
+
const key = announcementKey(announcement);
|
|
1148
|
+
const bucket = byKey.get(key);
|
|
1149
|
+
if (bucket) bucket.push(announcement);
|
|
1150
|
+
else byKey.set(key, [
|
|
1151
|
+
announcement
|
|
1152
|
+
]);
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
const out = [];
|
|
1156
|
+
for (const [key, announcements] of byKey) {
|
|
1157
|
+
const groups = stated(announcements.map((a) => a.group));
|
|
1158
|
+
const origins = stated(announcements.map((a) => a.origin));
|
|
1159
|
+
const requiresByJson = /* @__PURE__ */ new Map();
|
|
1160
|
+
for (const a of announcements) {
|
|
1161
|
+
if (a.requires === void 0) continue;
|
|
1162
|
+
const canonical = [
|
|
1163
|
+
...new Set(a.requires)
|
|
1164
|
+
].sort();
|
|
1165
|
+
requiresByJson.set(JSON.stringify(canonical), canonical);
|
|
1166
|
+
}
|
|
1167
|
+
const requires = [
|
|
1168
|
+
...requiresByJson.values()
|
|
1169
|
+
].sort((x, y) => x.join(",").localeCompare(y.join(",")));
|
|
1170
|
+
const disagreements = [];
|
|
1171
|
+
if (groups.length > 1) disagreements.push({
|
|
1172
|
+
axis: "group",
|
|
1173
|
+
values: groups
|
|
1174
|
+
});
|
|
1175
|
+
if (origins.length > 1) disagreements.push({
|
|
1176
|
+
axis: "origin",
|
|
1177
|
+
values: origins
|
|
1178
|
+
});
|
|
1179
|
+
if (requires.length > 1) {
|
|
1180
|
+
disagreements.push({
|
|
1181
|
+
axis: "requires",
|
|
1182
|
+
values: requires.map((r) => r.join(","))
|
|
1183
|
+
});
|
|
1184
|
+
}
|
|
1185
|
+
const first = announcements[0];
|
|
1186
|
+
if (!first) continue;
|
|
1187
|
+
out.push({
|
|
1188
|
+
key,
|
|
1189
|
+
name: first.name,
|
|
1190
|
+
...first.version !== void 0 ? {
|
|
1191
|
+
version: first.version
|
|
1192
|
+
} : {},
|
|
1193
|
+
groups,
|
|
1194
|
+
origins,
|
|
1195
|
+
requires,
|
|
1196
|
+
runtimes: [
|
|
1197
|
+
...new Set(announcements.map((a) => a.runtime))
|
|
1198
|
+
].sort(),
|
|
1199
|
+
instances: [
|
|
1200
|
+
...new Set(announcements.map((a) => a.instanceId))
|
|
1201
|
+
].sort(),
|
|
1202
|
+
disagreements
|
|
1203
|
+
});
|
|
1204
|
+
}
|
|
1205
|
+
return out.sort((a, b) => a.key.localeCompare(b.key));
|
|
1206
|
+
}
|
|
1207
|
+
__name(aggregateAnnouncements, "aggregateAnnouncements");
|
|
1047
1208
|
|
|
1048
1209
|
// src/handshake/negotiate.ts
|
|
1049
1210
|
var rangesOverlap = /* @__PURE__ */ __name((a, b) => Math.max(a[0], b[0]) <= Math.min(a[1], b[1]), "rangesOverlap");
|
|
@@ -1571,6 +1732,30 @@ var TransportPool = class {
|
|
|
1571
1732
|
}
|
|
1572
1733
|
return descriptors;
|
|
1573
1734
|
}
|
|
1735
|
+
/**
|
|
1736
|
+
* Every live descriptor in the deployment, merged across every transport that can report them and
|
|
1737
|
+
* de-duplicated by `instanceId` — one worker publishes the same descriptor under each token it
|
|
1738
|
+
* consumes, and it must count once. Returns `[]` when no transport implements
|
|
1739
|
+
* {@link Transport.readAllWorkerDescriptors} (a pure in-process pool advertises nothing).
|
|
1740
|
+
*
|
|
1741
|
+
* First writer wins on a duplicate id: the copies are the same bytes by construction (one process,
|
|
1742
|
+
* one descriptor, published N times), so there is nothing to choose between. Two DIFFERENT
|
|
1743
|
+
* processes sharing an `instanceId` would collapse into one here — that is a misconfiguration the
|
|
1744
|
+
* fleet already suffers from (they also share heartbeat and descriptor keys, so they overwrite each
|
|
1745
|
+
* other's advertisement), not something this read can repair.
|
|
1746
|
+
*/
|
|
1747
|
+
async readAllWorkerDescriptors() {
|
|
1748
|
+
const byInstance = /* @__PURE__ */ new Map();
|
|
1749
|
+
for (const { transport } of this.transports) {
|
|
1750
|
+
if (!transport.readAllWorkerDescriptors) continue;
|
|
1751
|
+
for (const descriptor of await transport.readAllWorkerDescriptors()) {
|
|
1752
|
+
if (!byInstance.has(descriptor.instanceId)) byInstance.set(descriptor.instanceId, descriptor);
|
|
1753
|
+
}
|
|
1754
|
+
}
|
|
1755
|
+
return [
|
|
1756
|
+
...byInstance.values()
|
|
1757
|
+
];
|
|
1758
|
+
}
|
|
1574
1759
|
/** Distinct worker groups with a live heartbeat, merged across every transport that can report it. */
|
|
1575
1760
|
async listWorkerGroups() {
|
|
1576
1761
|
const groups = /* @__PURE__ */ new Set();
|
|
@@ -1971,7 +2156,7 @@ function createWorkflowCtx(host, runId, compensations, workflow = "", searchAttr
|
|
|
1971
2156
|
return unwrapCompletion(await waitForSignal(`task:${runId}:${name}`), `task "${name}"`);
|
|
1972
2157
|
}, "task");
|
|
1973
2158
|
const child = /* @__PURE__ */ __name(async (workflow2, input, options) => {
|
|
1974
|
-
const { childId, priority } = normalizeChildOptions(options);
|
|
2159
|
+
const { childId, priority, version } = normalizeChildOptions(options);
|
|
1975
2160
|
const current = pos.next();
|
|
1976
2161
|
const id = childId ?? `${runId}.child.${current}`;
|
|
1977
2162
|
const existing = await readCheckpoint(current);
|
|
@@ -1999,7 +2184,7 @@ function createWorkflowCtx(host, runId, compensations, workflow = "", searchAttr
|
|
|
1999
2184
|
}));
|
|
2000
2185
|
return unwrapCompletion(buffered.payload, `child "${id}"`);
|
|
2001
2186
|
}
|
|
2002
|
-
if (!await store.getRun(id)) host.startChild(workflowName(workflow2), input, id, priority);
|
|
2187
|
+
if (!await store.getRun(id)) host.startChild(workflowName(workflow2), input, id, priority, version);
|
|
2003
2188
|
if (!existing) {
|
|
2004
2189
|
await writeCheckpoint(instantCheckpoint({
|
|
2005
2190
|
runId,
|
|
@@ -2082,12 +2267,12 @@ function createWorkflowCtx(host, runId, compensations, workflow = "", searchAttr
|
|
|
2082
2267
|
return outputs;
|
|
2083
2268
|
}, "all");
|
|
2084
2269
|
const startChild = /* @__PURE__ */ __name(async (workflow2, input, options) => {
|
|
2085
|
-
const { childId, priority } = normalizeChildOptions(options);
|
|
2270
|
+
const { childId, priority, version } = normalizeChildOptions(options);
|
|
2086
2271
|
const current = pos.next();
|
|
2087
2272
|
const id = childId ?? `${runId}.child.${current}`;
|
|
2088
2273
|
const existing = await readCheckpoint(current);
|
|
2089
2274
|
if (existing && existing.status === "completed") return existing.output;
|
|
2090
|
-
if (!await store.getRun(id)) host.startChild(workflowName(workflow2), input, id, priority);
|
|
2275
|
+
if (!await store.getRun(id)) host.startChild(workflowName(workflow2), input, id, priority, version);
|
|
2091
2276
|
await writeCheckpoint(instantCheckpoint({
|
|
2092
2277
|
runId,
|
|
2093
2278
|
seq: current,
|
|
@@ -2647,6 +2832,15 @@ var WorkflowEngine = class {
|
|
|
2647
2832
|
const reg = this.workflows.get(versionKey(name, version));
|
|
2648
2833
|
return reg?.hasBody ? reg.fn : void 0;
|
|
2649
2834
|
}
|
|
2835
|
+
/** The registered versions of `name`, for the pinned-start error — "2 is not registered" is a
|
|
2836
|
+
* guess-the-typo error without them, and the answer (which versions this deploy actually carries)
|
|
2837
|
+
* is right here. `none` when the name is unknown entirely. */
|
|
2838
|
+
registeredVersions(name) {
|
|
2839
|
+
const versions = [
|
|
2840
|
+
...this.workflows.values()
|
|
2841
|
+
].filter((w) => w.name === name).map((w) => w.version);
|
|
2842
|
+
return versions.length ? versions.join(", ") : "none";
|
|
2843
|
+
}
|
|
2650
2844
|
/**
|
|
2651
2845
|
* Register a workflow whose body runs in another SDK (e.g. Python). The engine owns the run exactly
|
|
2652
2846
|
* as for a TS workflow — it persists checkpoints, recovers, runs timers — but advances it by handing
|
|
@@ -2796,12 +2990,13 @@ var WorkflowEngine = class {
|
|
|
2796
2990
|
}
|
|
2797
2991
|
async start(workflow, input, runId, opts) {
|
|
2798
2992
|
const name = workflowName(workflow);
|
|
2799
|
-
|
|
2800
|
-
|
|
2993
|
+
const pinned = opts?.version;
|
|
2994
|
+
let registered = pinned === void 0 ? this.latest.get(name) : this.workflows.get(versionKey(name, pinned));
|
|
2995
|
+
if (!registered && pinned === void 0) {
|
|
2801
2996
|
const ancestor = await this.findRemoteAncestor(runId);
|
|
2802
2997
|
if (ancestor) registered = this.synthesizeRemoteChild(name, ancestor.version, ancestor);
|
|
2803
2998
|
}
|
|
2804
|
-
if (!registered) {
|
|
2999
|
+
if (!registered && pinned === void 0) {
|
|
2805
3000
|
const conventionRun = {
|
|
2806
3001
|
id: runId,
|
|
2807
3002
|
workflow: name,
|
|
@@ -2818,7 +3013,9 @@ var WorkflowEngine = class {
|
|
|
2818
3013
|
};
|
|
2819
3014
|
registered = await this.resolveRemoteByConvention(conventionRun);
|
|
2820
3015
|
}
|
|
2821
|
-
if (!registered)
|
|
3016
|
+
if (!registered) {
|
|
3017
|
+
throw new Error(pinned === void 0 ? `workflow ${name} is not registered` : `workflow ${versionKey(name, pinned)} is not registered \u2014 a pinned start never falls back to the newest version (registered: ${this.registeredVersions(name)})`);
|
|
3018
|
+
}
|
|
2822
3019
|
await registered.validateInput?.(input);
|
|
2823
3020
|
const prior = await this.store.getRun(runId);
|
|
2824
3021
|
if (prior) {
|
|
@@ -3025,7 +3222,32 @@ var WorkflowEngine = class {
|
|
|
3025
3222
|
/**
|
|
3026
3223
|
* Cancel in-flight runs that have outlived their workflow's `executionTimeout`. Call it from the
|
|
3027
3224
|
* timer poller alongside {@link resumeDueTimers}. A timed-out run is moved to `cancelled` with an
|
|
3028
|
-
* `execution_timeout` error (terminal, so a late step result can't resurrect it)
|
|
3225
|
+
* `execution_timeout` error (terminal, so a late step result can't resurrect it), AND its children
|
|
3226
|
+
* are cascaded exactly as an explicit {@link cancel} cascades them.
|
|
3227
|
+
*
|
|
3228
|
+
* WHY THE TERMINAL WRITE IS DIRECT, not a call to {@link cancel}. Two reasons, both still standing:
|
|
3229
|
+
* the run must land with the `execution_timeout` error `cancel` knows nothing about (`cancel` writes
|
|
3230
|
+
* a plain `cancelled`, and the code is what a dashboard/alert distinguishes a timeout by), and this
|
|
3231
|
+
* is a SCAN — it walks every in-flight run of every timed workflow on every poller tick, so it must
|
|
3232
|
+
* not pay `cancel`'s per-run re-read and singleton/control-plane work on runs it isn't cancelling.
|
|
3233
|
+
* The cascade below is charged only to the runs that ACTUALLY timed out, which are rare by
|
|
3234
|
+
* construction; the scan itself is unchanged.
|
|
3235
|
+
*
|
|
3236
|
+
* The subtree, though, has no reason to differ, and before this it did: a timed-out parent's
|
|
3237
|
+
* children kept running with the parent gone and nothing pointing at them — a silent orphan you
|
|
3238
|
+
* could only find by reading the runs table by hand. {@link cancelChildren} is the SAME recursive
|
|
3239
|
+
* walk `cancel` uses, so children of children go too, and it inherits that path's two guards:
|
|
3240
|
+
* `cancel` returns early on a run that is already `completed`/`cancelled`/`dead` (a child that beat
|
|
3241
|
+
* the sweep to the finish is never clobbered, and a re-cancel is a no-op), and it writes the
|
|
3242
|
+
* parent's terminal status BEFORE recursing, so a cyclic parent→child graph terminates on the
|
|
3243
|
+
* second visit instead of looping. Two pollers sweeping the same run concurrently therefore write
|
|
3244
|
+
* the same terminal state twice and cascade into already-cancelled children — idempotent, not
|
|
3245
|
+
* corrupting. The one window it does NOT close is the pre-existing check-then-write race an
|
|
3246
|
+
* explicit `cancel` has always had (a child that completes between `cancel`'s read and its write);
|
|
3247
|
+
* closing that needs a compare-and-set in the store contract, not a change here.
|
|
3248
|
+
*
|
|
3249
|
+
* Cascade failures are swallowed per subtree for the same reason `cancelChildren` swallows them per
|
|
3250
|
+
* child: one unreachable child must not abort the sweep and leave every LATER timed-out run alive.
|
|
3029
3251
|
*/
|
|
3030
3252
|
async sweepTimeouts(now = this.clock()) {
|
|
3031
3253
|
for (const reg of new Set(this.latest.values())) {
|
|
@@ -3061,6 +3283,7 @@ var WorkflowEngine = class {
|
|
|
3061
3283
|
namespace: run.namespace,
|
|
3062
3284
|
error: error2
|
|
3063
3285
|
});
|
|
3286
|
+
await this.cancelChildren(run.id).catch(() => void 0);
|
|
3064
3287
|
}
|
|
3065
3288
|
}
|
|
3066
3289
|
}
|
|
@@ -3789,6 +4012,10 @@ var WorkflowEngine = class {
|
|
|
3789
4012
|
* `child:<id>` waiter) and fire-and-forget (`ctx.startChild`, found via its `spawn:<id>`
|
|
3790
4013
|
* checkpoint). Recursive, so a whole subtree is cancelled; the terminal guard in `cancel` stops it
|
|
3791
4014
|
* at finished / already-cancelled runs (no loops, no re-cancel).
|
|
4015
|
+
*
|
|
4016
|
+
* Two callers, deliberately the same walk: an explicit {@link cancel}, and {@link sweepTimeouts}
|
|
4017
|
+
* when a parent hits its `executionTimeout` — a timed-out parent's subtree dies the same way an
|
|
4018
|
+
* explicitly cancelled one's does, or the children are orphans nobody is holding a reference to.
|
|
3792
4019
|
*/
|
|
3793
4020
|
async cancelChildren(parentRunId, opts) {
|
|
3794
4021
|
for (const id of await this.getRunChildren(parentRunId)) {
|
|
@@ -3868,6 +4095,29 @@ var WorkflowEngine = class {
|
|
|
3868
4095
|
return out;
|
|
3869
4096
|
}
|
|
3870
4097
|
/**
|
|
4098
|
+
* What workflows the LIVE fleet announces it can execute — the deployment-wide registry a picker
|
|
4099
|
+
* ("call this existing workflow") needs, and the one question this engine's own registry cannot
|
|
4100
|
+
* answer. {@link workflowBody} answers only for this process, and a missing body is ambiguous: it
|
|
4101
|
+
* means "not registered here", but equally "registered via {@link registerRemote} against another
|
|
4102
|
+
* SDK" or "a group resolved by convention against a worker". An inferred answer would therefore
|
|
4103
|
+
* differ per replica. This one does not: every pod folds the same published announcements.
|
|
4104
|
+
*
|
|
4105
|
+
* Scoped like every other poll surface — an engine WITH a `namespace` sees only workers in it, and
|
|
4106
|
+
* an operator (namespace unset) sees the whole deployment ("ver tudo = ausência de namespace"). A
|
|
4107
|
+
* descriptor that states no namespace is `default`, matching how a single-tenant fleet publishes.
|
|
4108
|
+
*
|
|
4109
|
+
* Cost: one advertisement scan per CALL, on demand. Nothing is added to the poll loop and nothing
|
|
4110
|
+
* is retained — no pod holds a table of the fleet's registrations. Empty when no transport can
|
|
4111
|
+
* introspect the advertisement keyspace (a pure in-process transport advertises nothing).
|
|
4112
|
+
*
|
|
4113
|
+
* Workflows only, and deliberately: see the "steps are out of scope" note in `handshake/announced`.
|
|
4114
|
+
*/
|
|
4115
|
+
async announcedWorkflows() {
|
|
4116
|
+
const descriptors = await this.pool.readAllWorkerDescriptors();
|
|
4117
|
+
const mine = this.namespace === void 0 ? descriptors : descriptors.filter((d) => (d.namespace ?? "default") === this.namespace);
|
|
4118
|
+
return aggregateAnnouncements(mine);
|
|
4119
|
+
}
|
|
4120
|
+
/**
|
|
3871
4121
|
* The routing groups of every in-flight run's still-`pending` remote step — the queues where work is
|
|
3872
4122
|
* dispatched and awaiting a worker. Folded into {@link workerHealth} so a step waiting on a group
|
|
3873
4123
|
* that is NEITHER a registration NOR heartbeating (the exact shape of a run stuck on an offline
|
|
@@ -4946,10 +5196,13 @@ var WorkflowEngine = class {
|
|
|
4946
5196
|
// namespace) is the one executing the parent. Otherwise an operator recovery-resuming a
|
|
4947
5197
|
// `davi-local` pipeline would stamp its `processing` child `default` and it would leak off the
|
|
4948
5198
|
// tenant's worker pool onto the shared/dev workers.
|
|
4949
|
-
startChild: /* @__PURE__ */ __name((workflow, input, id, priority) => {
|
|
5199
|
+
startChild: /* @__PURE__ */ __name((workflow, input, id, priority, version) => {
|
|
4950
5200
|
this.startChildDeferred(workflow, input, id, {
|
|
4951
5201
|
priority,
|
|
4952
|
-
namespace: parentNamespace
|
|
5202
|
+
namespace: parentNamespace,
|
|
5203
|
+
// Absent unless the body pinned one (`ctx.child(ref, input, { version })`) — an omitted
|
|
5204
|
+
// pin must stay omitted, so the child keeps resolving `latest` exactly as before.
|
|
5205
|
+
version
|
|
4953
5206
|
});
|
|
4954
5207
|
}, "startChild"),
|
|
4955
5208
|
// Deferred for the same reentrancy reason as `startChild` above. `cancel()` is already
|
|
@@ -6357,6 +6610,8 @@ export {
|
|
|
6357
6610
|
WorkflowBlocked,
|
|
6358
6611
|
WorkflowEngine,
|
|
6359
6612
|
WorkflowSuspended,
|
|
6613
|
+
aggregateAnnouncements,
|
|
6614
|
+
announcementsOf,
|
|
6360
6615
|
applyAttributeQuery,
|
|
6361
6616
|
attributeColumnFor,
|
|
6362
6617
|
attributeOperand,
|
|
@@ -6372,6 +6627,7 @@ export {
|
|
|
6372
6627
|
currentStep,
|
|
6373
6628
|
currentWorkflowCtx,
|
|
6374
6629
|
debug,
|
|
6630
|
+
describeWorker,
|
|
6375
6631
|
descriptorHash,
|
|
6376
6632
|
error,
|
|
6377
6633
|
eventMatchOf,
|