@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.cjs
CHANGED
|
@@ -60,6 +60,8 @@ __export(index_exports, {
|
|
|
60
60
|
WorkflowBlocked: () => WorkflowBlocked,
|
|
61
61
|
WorkflowEngine: () => WorkflowEngine,
|
|
62
62
|
WorkflowSuspended: () => WorkflowSuspended,
|
|
63
|
+
aggregateAnnouncements: () => aggregateAnnouncements,
|
|
64
|
+
announcementsOf: () => announcementsOf,
|
|
63
65
|
applyAttributeQuery: () => applyAttributeQuery,
|
|
64
66
|
attributeColumnFor: () => attributeColumnFor,
|
|
65
67
|
attributeOperand: () => attributeOperand,
|
|
@@ -75,6 +77,7 @@ __export(index_exports, {
|
|
|
75
77
|
currentStep: () => currentStep,
|
|
76
78
|
currentWorkflowCtx: () => currentWorkflowCtx,
|
|
77
79
|
debug: () => debug,
|
|
80
|
+
describeWorker: () => describeWorker,
|
|
78
81
|
descriptorHash: () => descriptorHash,
|
|
79
82
|
error: () => error,
|
|
80
83
|
eventMatchOf: () => eventMatchOf,
|
|
@@ -1103,6 +1106,9 @@ function normalizeDescriptor(raw) {
|
|
|
1103
1106
|
],
|
|
1104
1107
|
workflows: raw.workflows ?? [],
|
|
1105
1108
|
steps: raw.steps ?? [],
|
|
1109
|
+
...raw.registrations !== void 0 ? {
|
|
1110
|
+
registrations: raw.registrations
|
|
1111
|
+
} : {},
|
|
1106
1112
|
...raw.partition !== void 0 ? {
|
|
1107
1113
|
partition: raw.partition
|
|
1108
1114
|
} : {},
|
|
@@ -1113,6 +1119,23 @@ function normalizeDescriptor(raw) {
|
|
|
1113
1119
|
};
|
|
1114
1120
|
}
|
|
1115
1121
|
__name(normalizeDescriptor, "normalizeDescriptor");
|
|
1122
|
+
function canonicalizeRegistrations(regs) {
|
|
1123
|
+
const canonical = regs.map((r) => ({
|
|
1124
|
+
name: r.name,
|
|
1125
|
+
version: r.version ?? null,
|
|
1126
|
+
group: r.group ?? null,
|
|
1127
|
+
requires: r.requires ? [
|
|
1128
|
+
...new Set(r.requires)
|
|
1129
|
+
].sort() : null,
|
|
1130
|
+
origin: r.origin ?? null
|
|
1131
|
+
}));
|
|
1132
|
+
const byJson = /* @__PURE__ */ new Map();
|
|
1133
|
+
for (const entry of canonical) byJson.set(JSON.stringify(entry), entry);
|
|
1134
|
+
return [
|
|
1135
|
+
...byJson.keys()
|
|
1136
|
+
].sort().map((k) => byJson.get(k));
|
|
1137
|
+
}
|
|
1138
|
+
__name(canonicalizeRegistrations, "canonicalizeRegistrations");
|
|
1116
1139
|
function canonicalizeForHash(d) {
|
|
1117
1140
|
const set = /* @__PURE__ */ __name((xs) => [
|
|
1118
1141
|
...new Set(xs)
|
|
@@ -1134,6 +1157,9 @@ function canonicalizeForHash(d) {
|
|
|
1134
1157
|
capabilities: set(d.capabilities),
|
|
1135
1158
|
workflows: set(d.workflows),
|
|
1136
1159
|
steps: set(d.steps),
|
|
1160
|
+
...d.registrations !== void 0 ? {
|
|
1161
|
+
registrations: canonicalizeRegistrations(d.registrations)
|
|
1162
|
+
} : {},
|
|
1137
1163
|
partition: d.partition ?? null,
|
|
1138
1164
|
namespace: d.namespace ?? null,
|
|
1139
1165
|
startedAt: d.startedAt
|
|
@@ -1166,6 +1192,144 @@ function heartbeatStatus(descriptor, opts = {}) {
|
|
|
1166
1192
|
};
|
|
1167
1193
|
}
|
|
1168
1194
|
__name(heartbeatStatus, "heartbeatStatus");
|
|
1195
|
+
function describeWorker(opts) {
|
|
1196
|
+
const version = CURRENT_PROTOCOL_VERSION;
|
|
1197
|
+
const registrations = [
|
|
1198
|
+
...opts.registrations ?? []
|
|
1199
|
+
].sort((a, b) => `${a.name}@${a.version ?? ""}`.localeCompare(`${b.name}@${b.version ?? ""}`));
|
|
1200
|
+
return {
|
|
1201
|
+
instanceId: opts.instanceId,
|
|
1202
|
+
runtime: opts.runtime,
|
|
1203
|
+
sdk: {
|
|
1204
|
+
name: opts.sdk.name,
|
|
1205
|
+
version: opts.sdk.version
|
|
1206
|
+
},
|
|
1207
|
+
protocol: {
|
|
1208
|
+
version,
|
|
1209
|
+
range: [
|
|
1210
|
+
version,
|
|
1211
|
+
version
|
|
1212
|
+
]
|
|
1213
|
+
},
|
|
1214
|
+
capabilities: [
|
|
1215
|
+
...LEGACY_V1_CAPABILITIES
|
|
1216
|
+
],
|
|
1217
|
+
workflows: [
|
|
1218
|
+
...opts.workflows ?? []
|
|
1219
|
+
].sort(),
|
|
1220
|
+
steps: [
|
|
1221
|
+
...opts.steps
|
|
1222
|
+
].sort(),
|
|
1223
|
+
...registrations.length > 0 ? {
|
|
1224
|
+
registrations
|
|
1225
|
+
} : {},
|
|
1226
|
+
...opts.partition ? {
|
|
1227
|
+
partition: opts.partition
|
|
1228
|
+
} : {},
|
|
1229
|
+
...opts.namespace && opts.namespace !== "default" ? {
|
|
1230
|
+
namespace: opts.namespace
|
|
1231
|
+
} : {},
|
|
1232
|
+
startedAt: opts.startedAt
|
|
1233
|
+
};
|
|
1234
|
+
}
|
|
1235
|
+
__name(describeWorker, "describeWorker");
|
|
1236
|
+
|
|
1237
|
+
// src/handshake/announced.ts
|
|
1238
|
+
function announcementsOf(raw) {
|
|
1239
|
+
const d = normalizeDescriptor(raw);
|
|
1240
|
+
const identity = {
|
|
1241
|
+
instanceId: d.instanceId,
|
|
1242
|
+
runtime: d.runtime
|
|
1243
|
+
};
|
|
1244
|
+
const announcements = (d.registrations ?? []).map((reg) => ({
|
|
1245
|
+
...reg,
|
|
1246
|
+
...identity
|
|
1247
|
+
}));
|
|
1248
|
+
const covered = new Set(announcements.map((a) => a.name));
|
|
1249
|
+
for (const name of d.workflows) {
|
|
1250
|
+
if (!covered.has(name)) announcements.push({
|
|
1251
|
+
name,
|
|
1252
|
+
...identity
|
|
1253
|
+
});
|
|
1254
|
+
}
|
|
1255
|
+
return announcements;
|
|
1256
|
+
}
|
|
1257
|
+
__name(announcementsOf, "announcementsOf");
|
|
1258
|
+
function announcementKey(a) {
|
|
1259
|
+
return a.version === void 0 ? a.name : `${a.name}@${a.version}`;
|
|
1260
|
+
}
|
|
1261
|
+
__name(announcementKey, "announcementKey");
|
|
1262
|
+
function stated(values) {
|
|
1263
|
+
return [
|
|
1264
|
+
...new Set(values.filter((v) => v !== void 0))
|
|
1265
|
+
].sort();
|
|
1266
|
+
}
|
|
1267
|
+
__name(stated, "stated");
|
|
1268
|
+
function aggregateAnnouncements(descriptors) {
|
|
1269
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
1270
|
+
for (const descriptor of descriptors) {
|
|
1271
|
+
for (const announcement of announcementsOf(descriptor)) {
|
|
1272
|
+
const key = announcementKey(announcement);
|
|
1273
|
+
const bucket = byKey.get(key);
|
|
1274
|
+
if (bucket) bucket.push(announcement);
|
|
1275
|
+
else byKey.set(key, [
|
|
1276
|
+
announcement
|
|
1277
|
+
]);
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
const out = [];
|
|
1281
|
+
for (const [key, announcements] of byKey) {
|
|
1282
|
+
const groups = stated(announcements.map((a) => a.group));
|
|
1283
|
+
const origins = stated(announcements.map((a) => a.origin));
|
|
1284
|
+
const requiresByJson = /* @__PURE__ */ new Map();
|
|
1285
|
+
for (const a of announcements) {
|
|
1286
|
+
if (a.requires === void 0) continue;
|
|
1287
|
+
const canonical = [
|
|
1288
|
+
...new Set(a.requires)
|
|
1289
|
+
].sort();
|
|
1290
|
+
requiresByJson.set(JSON.stringify(canonical), canonical);
|
|
1291
|
+
}
|
|
1292
|
+
const requires = [
|
|
1293
|
+
...requiresByJson.values()
|
|
1294
|
+
].sort((x, y) => x.join(",").localeCompare(y.join(",")));
|
|
1295
|
+
const disagreements = [];
|
|
1296
|
+
if (groups.length > 1) disagreements.push({
|
|
1297
|
+
axis: "group",
|
|
1298
|
+
values: groups
|
|
1299
|
+
});
|
|
1300
|
+
if (origins.length > 1) disagreements.push({
|
|
1301
|
+
axis: "origin",
|
|
1302
|
+
values: origins
|
|
1303
|
+
});
|
|
1304
|
+
if (requires.length > 1) {
|
|
1305
|
+
disagreements.push({
|
|
1306
|
+
axis: "requires",
|
|
1307
|
+
values: requires.map((r) => r.join(","))
|
|
1308
|
+
});
|
|
1309
|
+
}
|
|
1310
|
+
const first = announcements[0];
|
|
1311
|
+
if (!first) continue;
|
|
1312
|
+
out.push({
|
|
1313
|
+
key,
|
|
1314
|
+
name: first.name,
|
|
1315
|
+
...first.version !== void 0 ? {
|
|
1316
|
+
version: first.version
|
|
1317
|
+
} : {},
|
|
1318
|
+
groups,
|
|
1319
|
+
origins,
|
|
1320
|
+
requires,
|
|
1321
|
+
runtimes: [
|
|
1322
|
+
...new Set(announcements.map((a) => a.runtime))
|
|
1323
|
+
].sort(),
|
|
1324
|
+
instances: [
|
|
1325
|
+
...new Set(announcements.map((a) => a.instanceId))
|
|
1326
|
+
].sort(),
|
|
1327
|
+
disagreements
|
|
1328
|
+
});
|
|
1329
|
+
}
|
|
1330
|
+
return out.sort((a, b) => a.key.localeCompare(b.key));
|
|
1331
|
+
}
|
|
1332
|
+
__name(aggregateAnnouncements, "aggregateAnnouncements");
|
|
1169
1333
|
|
|
1170
1334
|
// src/handshake/negotiate.ts
|
|
1171
1335
|
var rangesOverlap = /* @__PURE__ */ __name((a, b) => Math.max(a[0], b[0]) <= Math.min(a[1], b[1]), "rangesOverlap");
|
|
@@ -1693,6 +1857,30 @@ var TransportPool = class {
|
|
|
1693
1857
|
}
|
|
1694
1858
|
return descriptors;
|
|
1695
1859
|
}
|
|
1860
|
+
/**
|
|
1861
|
+
* Every live descriptor in the deployment, merged across every transport that can report them and
|
|
1862
|
+
* de-duplicated by `instanceId` — one worker publishes the same descriptor under each token it
|
|
1863
|
+
* consumes, and it must count once. Returns `[]` when no transport implements
|
|
1864
|
+
* {@link Transport.readAllWorkerDescriptors} (a pure in-process pool advertises nothing).
|
|
1865
|
+
*
|
|
1866
|
+
* First writer wins on a duplicate id: the copies are the same bytes by construction (one process,
|
|
1867
|
+
* one descriptor, published N times), so there is nothing to choose between. Two DIFFERENT
|
|
1868
|
+
* processes sharing an `instanceId` would collapse into one here — that is a misconfiguration the
|
|
1869
|
+
* fleet already suffers from (they also share heartbeat and descriptor keys, so they overwrite each
|
|
1870
|
+
* other's advertisement), not something this read can repair.
|
|
1871
|
+
*/
|
|
1872
|
+
async readAllWorkerDescriptors() {
|
|
1873
|
+
const byInstance = /* @__PURE__ */ new Map();
|
|
1874
|
+
for (const { transport } of this.transports) {
|
|
1875
|
+
if (!transport.readAllWorkerDescriptors) continue;
|
|
1876
|
+
for (const descriptor of await transport.readAllWorkerDescriptors()) {
|
|
1877
|
+
if (!byInstance.has(descriptor.instanceId)) byInstance.set(descriptor.instanceId, descriptor);
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1880
|
+
return [
|
|
1881
|
+
...byInstance.values()
|
|
1882
|
+
];
|
|
1883
|
+
}
|
|
1696
1884
|
/** Distinct worker groups with a live heartbeat, merged across every transport that can report it. */
|
|
1697
1885
|
async listWorkerGroups() {
|
|
1698
1886
|
const groups = /* @__PURE__ */ new Set();
|
|
@@ -2093,7 +2281,7 @@ function createWorkflowCtx(host, runId, compensations, workflow = "", searchAttr
|
|
|
2093
2281
|
return unwrapCompletion(await waitForSignal(`task:${runId}:${name}`), `task "${name}"`);
|
|
2094
2282
|
}, "task");
|
|
2095
2283
|
const child = /* @__PURE__ */ __name(async (workflow2, input, options) => {
|
|
2096
|
-
const { childId, priority } = normalizeChildOptions(options);
|
|
2284
|
+
const { childId, priority, version } = normalizeChildOptions(options);
|
|
2097
2285
|
const current = pos.next();
|
|
2098
2286
|
const id = childId ?? `${runId}.child.${current}`;
|
|
2099
2287
|
const existing = await readCheckpoint(current);
|
|
@@ -2121,7 +2309,7 @@ function createWorkflowCtx(host, runId, compensations, workflow = "", searchAttr
|
|
|
2121
2309
|
}));
|
|
2122
2310
|
return unwrapCompletion(buffered.payload, `child "${id}"`);
|
|
2123
2311
|
}
|
|
2124
|
-
if (!await store.getRun(id)) host.startChild(workflowName(workflow2), input, id, priority);
|
|
2312
|
+
if (!await store.getRun(id)) host.startChild(workflowName(workflow2), input, id, priority, version);
|
|
2125
2313
|
if (!existing) {
|
|
2126
2314
|
await writeCheckpoint(instantCheckpoint({
|
|
2127
2315
|
runId,
|
|
@@ -2204,12 +2392,12 @@ function createWorkflowCtx(host, runId, compensations, workflow = "", searchAttr
|
|
|
2204
2392
|
return outputs;
|
|
2205
2393
|
}, "all");
|
|
2206
2394
|
const startChild = /* @__PURE__ */ __name(async (workflow2, input, options) => {
|
|
2207
|
-
const { childId, priority } = normalizeChildOptions(options);
|
|
2395
|
+
const { childId, priority, version } = normalizeChildOptions(options);
|
|
2208
2396
|
const current = pos.next();
|
|
2209
2397
|
const id = childId ?? `${runId}.child.${current}`;
|
|
2210
2398
|
const existing = await readCheckpoint(current);
|
|
2211
2399
|
if (existing && existing.status === "completed") return existing.output;
|
|
2212
|
-
if (!await store.getRun(id)) host.startChild(workflowName(workflow2), input, id, priority);
|
|
2400
|
+
if (!await store.getRun(id)) host.startChild(workflowName(workflow2), input, id, priority, version);
|
|
2213
2401
|
await writeCheckpoint(instantCheckpoint({
|
|
2214
2402
|
runId,
|
|
2215
2403
|
seq: current,
|
|
@@ -2769,6 +2957,15 @@ var WorkflowEngine = class {
|
|
|
2769
2957
|
const reg = this.workflows.get(versionKey(name, version));
|
|
2770
2958
|
return reg?.hasBody ? reg.fn : void 0;
|
|
2771
2959
|
}
|
|
2960
|
+
/** The registered versions of `name`, for the pinned-start error — "2 is not registered" is a
|
|
2961
|
+
* guess-the-typo error without them, and the answer (which versions this deploy actually carries)
|
|
2962
|
+
* is right here. `none` when the name is unknown entirely. */
|
|
2963
|
+
registeredVersions(name) {
|
|
2964
|
+
const versions = [
|
|
2965
|
+
...this.workflows.values()
|
|
2966
|
+
].filter((w) => w.name === name).map((w) => w.version);
|
|
2967
|
+
return versions.length ? versions.join(", ") : "none";
|
|
2968
|
+
}
|
|
2772
2969
|
/**
|
|
2773
2970
|
* Register a workflow whose body runs in another SDK (e.g. Python). The engine owns the run exactly
|
|
2774
2971
|
* as for a TS workflow — it persists checkpoints, recovers, runs timers — but advances it by handing
|
|
@@ -2918,12 +3115,13 @@ var WorkflowEngine = class {
|
|
|
2918
3115
|
}
|
|
2919
3116
|
async start(workflow, input, runId, opts) {
|
|
2920
3117
|
const name = workflowName(workflow);
|
|
2921
|
-
|
|
2922
|
-
|
|
3118
|
+
const pinned = opts?.version;
|
|
3119
|
+
let registered = pinned === void 0 ? this.latest.get(name) : this.workflows.get(versionKey(name, pinned));
|
|
3120
|
+
if (!registered && pinned === void 0) {
|
|
2923
3121
|
const ancestor = await this.findRemoteAncestor(runId);
|
|
2924
3122
|
if (ancestor) registered = this.synthesizeRemoteChild(name, ancestor.version, ancestor);
|
|
2925
3123
|
}
|
|
2926
|
-
if (!registered) {
|
|
3124
|
+
if (!registered && pinned === void 0) {
|
|
2927
3125
|
const conventionRun = {
|
|
2928
3126
|
id: runId,
|
|
2929
3127
|
workflow: name,
|
|
@@ -2940,7 +3138,9 @@ var WorkflowEngine = class {
|
|
|
2940
3138
|
};
|
|
2941
3139
|
registered = await this.resolveRemoteByConvention(conventionRun);
|
|
2942
3140
|
}
|
|
2943
|
-
if (!registered)
|
|
3141
|
+
if (!registered) {
|
|
3142
|
+
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)})`);
|
|
3143
|
+
}
|
|
2944
3144
|
await registered.validateInput?.(input);
|
|
2945
3145
|
const prior = await this.store.getRun(runId);
|
|
2946
3146
|
if (prior) {
|
|
@@ -3147,7 +3347,32 @@ var WorkflowEngine = class {
|
|
|
3147
3347
|
/**
|
|
3148
3348
|
* Cancel in-flight runs that have outlived their workflow's `executionTimeout`. Call it from the
|
|
3149
3349
|
* timer poller alongside {@link resumeDueTimers}. A timed-out run is moved to `cancelled` with an
|
|
3150
|
-
* `execution_timeout` error (terminal, so a late step result can't resurrect it)
|
|
3350
|
+
* `execution_timeout` error (terminal, so a late step result can't resurrect it), AND its children
|
|
3351
|
+
* are cascaded exactly as an explicit {@link cancel} cascades them.
|
|
3352
|
+
*
|
|
3353
|
+
* WHY THE TERMINAL WRITE IS DIRECT, not a call to {@link cancel}. Two reasons, both still standing:
|
|
3354
|
+
* the run must land with the `execution_timeout` error `cancel` knows nothing about (`cancel` writes
|
|
3355
|
+
* a plain `cancelled`, and the code is what a dashboard/alert distinguishes a timeout by), and this
|
|
3356
|
+
* is a SCAN — it walks every in-flight run of every timed workflow on every poller tick, so it must
|
|
3357
|
+
* not pay `cancel`'s per-run re-read and singleton/control-plane work on runs it isn't cancelling.
|
|
3358
|
+
* The cascade below is charged only to the runs that ACTUALLY timed out, which are rare by
|
|
3359
|
+
* construction; the scan itself is unchanged.
|
|
3360
|
+
*
|
|
3361
|
+
* The subtree, though, has no reason to differ, and before this it did: a timed-out parent's
|
|
3362
|
+
* children kept running with the parent gone and nothing pointing at them — a silent orphan you
|
|
3363
|
+
* could only find by reading the runs table by hand. {@link cancelChildren} is the SAME recursive
|
|
3364
|
+
* walk `cancel` uses, so children of children go too, and it inherits that path's two guards:
|
|
3365
|
+
* `cancel` returns early on a run that is already `completed`/`cancelled`/`dead` (a child that beat
|
|
3366
|
+
* the sweep to the finish is never clobbered, and a re-cancel is a no-op), and it writes the
|
|
3367
|
+
* parent's terminal status BEFORE recursing, so a cyclic parent→child graph terminates on the
|
|
3368
|
+
* second visit instead of looping. Two pollers sweeping the same run concurrently therefore write
|
|
3369
|
+
* the same terminal state twice and cascade into already-cancelled children — idempotent, not
|
|
3370
|
+
* corrupting. The one window it does NOT close is the pre-existing check-then-write race an
|
|
3371
|
+
* explicit `cancel` has always had (a child that completes between `cancel`'s read and its write);
|
|
3372
|
+
* closing that needs a compare-and-set in the store contract, not a change here.
|
|
3373
|
+
*
|
|
3374
|
+
* Cascade failures are swallowed per subtree for the same reason `cancelChildren` swallows them per
|
|
3375
|
+
* child: one unreachable child must not abort the sweep and leave every LATER timed-out run alive.
|
|
3151
3376
|
*/
|
|
3152
3377
|
async sweepTimeouts(now = this.clock()) {
|
|
3153
3378
|
for (const reg of new Set(this.latest.values())) {
|
|
@@ -3183,6 +3408,7 @@ var WorkflowEngine = class {
|
|
|
3183
3408
|
namespace: run.namespace,
|
|
3184
3409
|
error: error2
|
|
3185
3410
|
});
|
|
3411
|
+
await this.cancelChildren(run.id).catch(() => void 0);
|
|
3186
3412
|
}
|
|
3187
3413
|
}
|
|
3188
3414
|
}
|
|
@@ -3911,6 +4137,10 @@ var WorkflowEngine = class {
|
|
|
3911
4137
|
* `child:<id>` waiter) and fire-and-forget (`ctx.startChild`, found via its `spawn:<id>`
|
|
3912
4138
|
* checkpoint). Recursive, so a whole subtree is cancelled; the terminal guard in `cancel` stops it
|
|
3913
4139
|
* at finished / already-cancelled runs (no loops, no re-cancel).
|
|
4140
|
+
*
|
|
4141
|
+
* Two callers, deliberately the same walk: an explicit {@link cancel}, and {@link sweepTimeouts}
|
|
4142
|
+
* when a parent hits its `executionTimeout` — a timed-out parent's subtree dies the same way an
|
|
4143
|
+
* explicitly cancelled one's does, or the children are orphans nobody is holding a reference to.
|
|
3914
4144
|
*/
|
|
3915
4145
|
async cancelChildren(parentRunId, opts) {
|
|
3916
4146
|
for (const id of await this.getRunChildren(parentRunId)) {
|
|
@@ -3990,6 +4220,29 @@ var WorkflowEngine = class {
|
|
|
3990
4220
|
return out;
|
|
3991
4221
|
}
|
|
3992
4222
|
/**
|
|
4223
|
+
* What workflows the LIVE fleet announces it can execute — the deployment-wide registry a picker
|
|
4224
|
+
* ("call this existing workflow") needs, and the one question this engine's own registry cannot
|
|
4225
|
+
* answer. {@link workflowBody} answers only for this process, and a missing body is ambiguous: it
|
|
4226
|
+
* means "not registered here", but equally "registered via {@link registerRemote} against another
|
|
4227
|
+
* SDK" or "a group resolved by convention against a worker". An inferred answer would therefore
|
|
4228
|
+
* differ per replica. This one does not: every pod folds the same published announcements.
|
|
4229
|
+
*
|
|
4230
|
+
* Scoped like every other poll surface — an engine WITH a `namespace` sees only workers in it, and
|
|
4231
|
+
* an operator (namespace unset) sees the whole deployment ("ver tudo = ausência de namespace"). A
|
|
4232
|
+
* descriptor that states no namespace is `default`, matching how a single-tenant fleet publishes.
|
|
4233
|
+
*
|
|
4234
|
+
* Cost: one advertisement scan per CALL, on demand. Nothing is added to the poll loop and nothing
|
|
4235
|
+
* is retained — no pod holds a table of the fleet's registrations. Empty when no transport can
|
|
4236
|
+
* introspect the advertisement keyspace (a pure in-process transport advertises nothing).
|
|
4237
|
+
*
|
|
4238
|
+
* Workflows only, and deliberately: see the "steps are out of scope" note in `handshake/announced`.
|
|
4239
|
+
*/
|
|
4240
|
+
async announcedWorkflows() {
|
|
4241
|
+
const descriptors = await this.pool.readAllWorkerDescriptors();
|
|
4242
|
+
const mine = this.namespace === void 0 ? descriptors : descriptors.filter((d) => (d.namespace ?? "default") === this.namespace);
|
|
4243
|
+
return aggregateAnnouncements(mine);
|
|
4244
|
+
}
|
|
4245
|
+
/**
|
|
3993
4246
|
* The routing groups of every in-flight run's still-`pending` remote step — the queues where work is
|
|
3994
4247
|
* dispatched and awaiting a worker. Folded into {@link workerHealth} so a step waiting on a group
|
|
3995
4248
|
* that is NEITHER a registration NOR heartbeating (the exact shape of a run stuck on an offline
|
|
@@ -5068,10 +5321,13 @@ var WorkflowEngine = class {
|
|
|
5068
5321
|
// namespace) is the one executing the parent. Otherwise an operator recovery-resuming a
|
|
5069
5322
|
// `davi-local` pipeline would stamp its `processing` child `default` and it would leak off the
|
|
5070
5323
|
// tenant's worker pool onto the shared/dev workers.
|
|
5071
|
-
startChild: /* @__PURE__ */ __name((workflow, input, id, priority) => {
|
|
5324
|
+
startChild: /* @__PURE__ */ __name((workflow, input, id, priority, version) => {
|
|
5072
5325
|
this.startChildDeferred(workflow, input, id, {
|
|
5073
5326
|
priority,
|
|
5074
|
-
namespace: parentNamespace
|
|
5327
|
+
namespace: parentNamespace,
|
|
5328
|
+
// Absent unless the body pinned one (`ctx.child(ref, input, { version })`) — an omitted
|
|
5329
|
+
// pin must stay omitted, so the child keeps resolving `latest` exactly as before.
|
|
5330
|
+
version
|
|
5075
5331
|
});
|
|
5076
5332
|
}, "startChild"),
|
|
5077
5333
|
// Deferred for the same reentrancy reason as `startChild` above. `cancel()` is already
|
|
@@ -6480,6 +6736,8 @@ var InMemoryTransport = class {
|
|
|
6480
6736
|
WorkflowBlocked,
|
|
6481
6737
|
WorkflowEngine,
|
|
6482
6738
|
WorkflowSuspended,
|
|
6739
|
+
aggregateAnnouncements,
|
|
6740
|
+
announcementsOf,
|
|
6483
6741
|
applyAttributeQuery,
|
|
6484
6742
|
attributeColumnFor,
|
|
6485
6743
|
attributeOperand,
|
|
@@ -6495,6 +6753,7 @@ var InMemoryTransport = class {
|
|
|
6495
6753
|
currentStep,
|
|
6496
6754
|
currentWorkflowCtx,
|
|
6497
6755
|
debug,
|
|
6756
|
+
describeWorker,
|
|
6498
6757
|
descriptorHash,
|
|
6499
6758
|
error,
|
|
6500
6759
|
eventMatchOf,
|