@voltro/workflow 0.70.0 → 0.71.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.
@@ -1,2666 +0,0 @@
1
- import { E as e, F as t, I as n, M as r, N as i, P as a, T as o, w as s } from "./primitives-CqHxfASq.js";
2
- import { Activity as c, DurableClock as l, DurableDeferred as u, Workflow as d, WorkflowEngine as f } from "@effect/workflow";
3
- import { Cause as p, Effect as m, Either as h, Exit as g, FiberRef as _, Layer as v, Schema as y } from "effect";
4
- import { publishServerError as ee } from "@voltro/protocol";
5
- import { and as b, boolean as te, eq as x, generateId as S, gt as C, gte as ne, id as w, inSet as re, integer as T, isNull as E, json as D, lt as O, or as ie, queryFor as k, reference as ae, registerRetention as oe, retentionTtlMsFromEnv as se, table as A, text as j, timestamp as M } from "@voltro/database";
6
- import { createHash as ce } from "node:crypto";
7
- import { WorkflowInstance as le } from "@effect/workflow/WorkflowEngine";
8
- //#region src/inMemoryLayer.ts
9
- var ue = f.layerMemory, de = A("_voltro_workflow_runs", {
10
- id: w({ prefix: "wfrun" }),
11
- tag: j(),
12
- executionId: j().unique(),
13
- status: j().oneOf([
14
- "running",
15
- "succeeded",
16
- "failed",
17
- "cancelled",
18
- "suspended"
19
- ]).default("running"),
20
- payload: D(),
21
- workflowVersion: j().nullable(),
22
- workflowPatches: D().nullable(),
23
- runnerEnteredAt: M().nullable(),
24
- reclaimCount: T().default(0),
25
- output: D().nullable(),
26
- subject: D().nullable(),
27
- source: j().nullable(),
28
- errorTag: j().nullable(),
29
- errorMessage: j().nullable(),
30
- cancelled: te().default(!1),
31
- discardedAt: M().nullable(),
32
- discardedBy: j().nullable(),
33
- startedAt: M().default("now"),
34
- completedAt: M().nullable(),
35
- durationMs: T().nullable(),
36
- traceId: j().nullable(),
37
- parentExecutionId: j().nullable(),
38
- parentClosePolicy: j().oneOf([
39
- "cancel",
40
- "terminate",
41
- "abandon"
42
- ]).nullable()
43
- }).index(["tag"]).index(["status"]).index(["source"]).index(["startedAt"]).index(["parentExecutionId"]).index(["parentClosePolicy"]), fe = A("_voltro_workflow_run_steps", {
44
- id: w({ prefix: "wfstep" }),
45
- runId: ae(() => de, {
46
- index: !1,
47
- onDelete: "cascade"
48
- }),
49
- stepName: j(),
50
- attempt: T().default(1),
51
- status: j().oneOf([
52
- "running",
53
- "succeeded",
54
- "failed"
55
- ]).default("running"),
56
- input: D().nullable(),
57
- retryPolicy: D().nullable(),
58
- output: D().nullable(),
59
- errorTag: j().nullable(),
60
- errorMessage: j().nullable(),
61
- errorCause: D().nullable(),
62
- startedAt: M().default("now"),
63
- completedAt: M().nullable(),
64
- durationMs: T().nullable()
65
- }).index(["runId", "stepName"]).index(["startedAt"]), pe = A("_voltro_workflow_run_events", {
66
- id: w({ prefix: "wfev" }),
67
- runId: ae(() => de, {
68
- index: !1,
69
- onDelete: "cascade"
70
- }),
71
- eventType: j(),
72
- payload: D().nullable(),
73
- occurredAt: M().default("now"),
74
- stepName: j().nullable(),
75
- attempt: T().nullable()
76
- }).index(["runId", "occurredAt"]).index(["eventType"]), me = A("_voltro_workflow_start_contexts", {
77
- id: w({ prefix: "wfctx" }),
78
- workflowName: j(),
79
- executionId: j().unique(),
80
- subject: D().nullable(),
81
- traceId: j().nullable(),
82
- source: j().nullable(),
83
- parentExecutionId: j().nullable(),
84
- parentClosePolicy: j().oneOf([
85
- "cancel",
86
- "terminate",
87
- "abandon"
88
- ]).nullable(),
89
- createdAt: M().default("now")
90
- }).index(["workflowName"]).index(["executionId"]).index(["parentExecutionId"]), he = A("_voltro_workflow_pending", {
91
- id: w({ prefix: "wfp" }),
92
- tenantId: j().nullable(),
93
- workflowName: j(),
94
- controlKey: j(),
95
- mode: j().oneOf([
96
- "debounce",
97
- "batch",
98
- "throttle",
99
- "concurrency",
100
- "paused",
101
- "delayed"
102
- ]),
103
- payload: D(),
104
- callerContext: D().nullable(),
105
- queuedAppVersion: j().nullable(),
106
- queuedSchemaFingerprint: j().nullable(),
107
- priority: T().default(0),
108
- dueAt: M(),
109
- deadlineAt: M().nullable(),
110
- collapsed: T().default(1),
111
- firstSeenAt: M().default("now"),
112
- updatedAt: M().default("now"),
113
- attempts: T().default(0),
114
- lastError: j().nullable(),
115
- deadLetteredAt: M().nullable()
116
- }).index(["workflowName", "controlKey"]).index(["dueAt"]).index(["workflowName", "mode"]).index(["tenantId"]), ge = A("_voltro_workflow_admissions", {
117
- id: w({ prefix: "wfadm" }),
118
- tenantId: j().nullable(),
119
- workflowName: j(),
120
- outcome: j().oneOf([
121
- "admitted",
122
- "dropped",
123
- "skipped",
124
- "evicted",
125
- "expired",
126
- "discarded"
127
- ]),
128
- mode: j().nullable(),
129
- reason: j().nullable(),
130
- collapsed: T().default(1),
131
- waitedMs: T().nullable(),
132
- executionId: j().nullable(),
133
- runId: j().nullable(),
134
- singletonKey: j().nullable(),
135
- concurrencyKey: j().nullable(),
136
- rateKey: j().nullable(),
137
- admittedAt: M().default("now"),
138
- expiresAt: M().nullable(),
139
- releasedAt: M().nullable()
140
- }).index(["workflowName", "admittedAt"]).index(["concurrencyKey", "releasedAt"]).index(["singletonKey", "releasedAt"]).index(["rateKey", "admittedAt"]).index(["executionId"]).index(["tenantId"]), _e = A("_voltro_workflow_pauses", {
141
- id: w({ prefix: "wfpause" }),
142
- pausedAt: M().default("now"),
143
- pausedBy: j().nullable(),
144
- reason: j().nullable()
145
- }), ve = class extends Error {
146
- workflowName;
147
- field;
148
- constructor(e, t, n) {
149
- super(`workflow '${e}': ${t}(payload) threw — a flow-control key function must be total over every payload the workflow accepts, because it runs before the run exists and there is nowhere to report a partial failure to. Cause: ${n instanceof Error ? n.message : String(n)}`), this.name = "FlowControlKeyError", this.workflowName = e, this.field = t, this.cause = n;
150
- }
151
- }, N = (e, t, n, r) => {
152
- try {
153
- let e = n(r);
154
- if (typeof e != "string" || e.length === 0) throw Error(`returned ${e === "" ? "an empty string" : String(e)}; expected a non-empty string`);
155
- return e;
156
- } catch (n) {
157
- throw new ve(e, t, n);
158
- }
159
- }, ye = (e, t) => e === void 0 ? t : `pool\u0000${e}\u0000${t}`, P = (e, t) => {
160
- let n = e.workflowName, r = 0;
161
- if (e.priority !== void 0) try {
162
- let n = e.priority(t);
163
- if (!Number.isFinite(n)) throw Error(`returned ${String(n)}; expected a finite number`);
164
- r = Math.trunc(n);
165
- } catch (e) {
166
- throw new ve(n, "priority", e);
167
- }
168
- return {
169
- ...e.debounce === void 0 ? {} : { debounceKey: N(n, "debounce.key", e.debounce.key, t) },
170
- ...e.singleton === void 0 ? {} : { singletonKey: N(n, "singleton.key", e.singleton.key, t) },
171
- ...e.concurrency === void 0 ? {} : { concurrencyKey: ye(e.concurrency.pool, e.concurrency.key === void 0 ? "" : N(n, "concurrency.key", e.concurrency.key, t)) },
172
- ...e.throttle?.key === void 0 ? e.throttle === void 0 ? {} : { throttleKey: "" } : { throttleKey: N(n, "throttle.key", e.throttle.key, t) },
173
- ...e.rateLimit?.key === void 0 ? e.rateLimit === void 0 ? {} : { rateLimitKey: "" } : { rateLimitKey: N(n, "rateLimit.key", e.rateLimit.key, t) },
174
- ...e.batch?.key === void 0 ? e.batch === void 0 ? {} : { batchKey: "" } : { batchKey: N(n, "batch.key", e.batch.key, t) },
175
- priority: r
176
- };
177
- }, be = (e, t, n, r) => {
178
- let i = e.filter((e) => e > r - n);
179
- if (i.length < t) return;
180
- let a = [...i].sort((e, t) => t - e)[t - 1];
181
- if (a !== void 0) return a + n;
182
- }, xe = (e) => {
183
- let { control: t, keys: n, state: r, now: i, reconsidering: a } = e;
184
- if (r.paused === !0) return {
185
- kind: "defer",
186
- mode: "paused",
187
- dueAt: i,
188
- collapse: a ? "hold" : "append",
189
- keys: n
190
- };
191
- if (t.rateLimit !== void 0) {
192
- let e = be(r.recentAdmissions ?? [], t.rateLimit.limit, t.rateLimit.periodMs, i);
193
- if (e !== void 0) return {
194
- kind: "drop",
195
- reason: "rate-limit",
196
- retryAfterMs: Math.max(0, e - i),
197
- keys: n
198
- };
199
- }
200
- if (t.singleton !== void 0 && t.singleton.mode === "skip" && r.singletonHolder !== void 0) return {
201
- kind: "skip",
202
- incumbent: r.singletonHolder,
203
- keys: n
204
- };
205
- if (t.debounce !== void 0) {
206
- let e = r.debouncePending, o = e?.firstSeenAt ?? i, s = e?.deadlineAt ?? (t.debounce.timeoutMs === void 0 ? void 0 : o + t.debounce.timeoutMs);
207
- return a ? s !== void 0 && i >= s ? {
208
- kind: "admit",
209
- reason: "debounce-deadline",
210
- keys: n,
211
- ...F(t, r)
212
- } : {
213
- kind: "admit",
214
- reason: "debounce-elapsed",
215
- keys: n,
216
- ...F(t, r)
217
- } : {
218
- kind: "defer",
219
- mode: "debounce",
220
- dueAt: s === void 0 ? i + t.debounce.periodMs : Math.min(i + t.debounce.periodMs, s),
221
- ...s === void 0 ? {} : { deadlineAt: s },
222
- collapse: "replace",
223
- keys: n
224
- };
225
- }
226
- if (t.batch !== void 0) {
227
- let e = r.batchPending, o = (e?.count ?? 0) + +!a, s = (e?.firstSeenAt ?? i) + t.batch.timeoutMs;
228
- return o >= t.batch.maxSize ? {
229
- kind: "admit",
230
- reason: "batch-full",
231
- keys: n,
232
- ...F(t, r)
233
- } : a && i >= s ? {
234
- kind: "admit",
235
- reason: "batch-timeout",
236
- keys: n,
237
- ...F(t, r)
238
- } : {
239
- kind: "defer",
240
- mode: "batch",
241
- dueAt: s,
242
- collapse: a ? "hold" : "append",
243
- keys: n
244
- };
245
- }
246
- if (t.throttle !== void 0) {
247
- let e = be(r.recentAdmissions ?? [], t.throttle.limit, t.throttle.periodMs, i);
248
- if (e !== void 0) return {
249
- kind: "defer",
250
- mode: "throttle",
251
- dueAt: e,
252
- collapse: a ? "hold" : "append",
253
- keys: n
254
- };
255
- }
256
- return t.concurrency !== void 0 && (r.inFlight ?? 0) >= t.concurrency.limit ? {
257
- kind: "defer",
258
- mode: "concurrency",
259
- dueAt: i,
260
- collapse: a ? "hold" : "append",
261
- keys: n
262
- } : {
263
- kind: "admit",
264
- reason: Se(t) ? "under-limits" : "no-controls",
265
- keys: n,
266
- ...F(t, r)
267
- };
268
- }, Se = (e) => e.debounce !== void 0 || e.singleton !== void 0 || e.concurrency !== void 0 || e.throttle !== void 0 || e.rateLimit !== void 0 || e.batch !== void 0, F = (e, t) => e.singleton?.mode === "cancel" && t.singletonHolder !== void 0 ? { evict: t.singletonHolder } : {}, Ce = (e, t, n) => {
269
- let r = e.timeouts?.startMs;
270
- return r !== void 0 && n - t.firstSeenAt >= r;
271
- }, we = (e, t, n) => {
272
- let r = e.timeouts?.finishMs;
273
- return r === void 0 || t.terminal ? !1 : n - t.startedAt >= r;
274
- }, Te = (e, t) => e.priority === t.priority ? e.firstSeenAt === t.firstSeenAt ? e.id < t.id ? -1 : +(e.id > t.id) : e.firstSeenAt - t.firstSeenAt : t.priority - e.priority, I = "_voltro_workflow_pending", L = "_voltro_workflow_admissions", Ee = "_voltro_workflow_pauses", De = 864e5, Oe = (e, t, n) => `wfp_${ce("sha256").update(`${e}\u0000${t}\u0000${n}`).digest("hex").slice(0, 40)}`, R = (e) => {
275
- if (e instanceof Date) return e.getTime();
276
- if (typeof e == "number") return e;
277
- let t = Date.parse(String(e));
278
- return Number.isNaN(t) ? 0 : t;
279
- }, z = (e, t) => {
280
- let n = typeof e == "number" ? e : Number(e);
281
- return Number.isFinite(n) ? Math.trunc(n) : t;
282
- }, ke = (e) => ({
283
- id: String(e.id),
284
- tenantId: e.tenantId === null || e.tenantId === void 0 ? null : String(e.tenantId),
285
- workflowName: String(e.workflowName),
286
- controlKey: String(e.controlKey ?? ""),
287
- mode: String(e.mode),
288
- payload: e.payload,
289
- callerContext: e.callerContext ?? null,
290
- queuedAppVersion: e.queuedAppVersion === null || e.queuedAppVersion === void 0 ? null : String(e.queuedAppVersion),
291
- queuedSchemaFingerprint: e.queuedSchemaFingerprint === null || e.queuedSchemaFingerprint === void 0 ? null : String(e.queuedSchemaFingerprint),
292
- priority: z(e.priority, 0),
293
- dueAt: R(e.dueAt),
294
- deadlineAt: e.deadlineAt === null || e.deadlineAt === void 0 ? void 0 : R(e.deadlineAt),
295
- collapsed: z(e.collapsed, 1),
296
- firstSeenAt: R(e.firstSeenAt),
297
- attempts: z(e.attempts, 0),
298
- lastError: e.lastError === null || e.lastError === void 0 ? null : String(e.lastError),
299
- deadLetteredAt: e.deadLetteredAt === null || e.deadLetteredAt === void 0 ? void 0 : R(e.deadLetteredAt)
300
- }), B = (e, t, n, r) => ({
301
- table: e,
302
- predicate: t,
303
- order: n,
304
- take: r,
305
- skip: void 0,
306
- projection: void 0
307
- }), Ae = async (e) => {
308
- let t = await e.query(B(Ee, void 0, [], 1e3));
309
- return new Set(t.map((e) => String(e.id)));
310
- }, je = async (e, t, n, r) => {
311
- await e.upsert(Ee, {
312
- id: t,
313
- pausedAt: /* @__PURE__ */ new Date(),
314
- pausedBy: n,
315
- reason: r
316
- }, {
317
- conflictColumns: ["id"],
318
- update: [
319
- "pausedAt",
320
- "pausedBy",
321
- "reason"
322
- ]
323
- });
324
- }, Me = async (e, t) => e.delete(Ee, t), Ne = async (e) => {
325
- let { store: t, control: n, keys: r, now: i } = e, a = { paused: e.paused }, o = [];
326
- n.debounce !== void 0 && r.debounceKey !== void 0 && o.push((async () => {
327
- let e = (await t.query(B(I, b(x("workflowName", n.workflowName), x("controlKey", r.debounceKey), x("mode", "debounce")), [], 1)))[0];
328
- if (e === void 0) return;
329
- let i = e.deadlineAt === null || e.deadlineAt === void 0 ? void 0 : R(e.deadlineAt);
330
- a.debouncePending = {
331
- firstSeenAt: R(e.firstSeenAt),
332
- collapsed: z(e.collapsed, 1),
333
- ...i === void 0 ? {} : { deadlineAt: i }
334
- };
335
- })()), n.batch !== void 0 && r.batchKey !== void 0 && o.push((async () => {
336
- let e = await t.query(B(I, b(x("workflowName", n.workflowName), x("controlKey", r.batchKey), x("mode", "batch")), [{
337
- column: "firstSeenAt",
338
- direction: "asc"
339
- }], n.batch.maxSize + 1));
340
- e.length !== 0 && (a.batchPending = {
341
- count: e.length,
342
- firstSeenAt: R(e[0].firstSeenAt)
343
- });
344
- })()), n.singleton !== void 0 && r.singletonKey !== void 0 && o.push((async () => {
345
- let e = await Pe(t, n.workflowName, r.singletonKey, i);
346
- e !== void 0 && (a.singletonHolder = e);
347
- })()), n.concurrency !== void 0 && r.concurrencyKey !== void 0 && o.push((async () => {
348
- let e = n.concurrency.pool === void 0 ? [x("workflowName", n.workflowName)] : [], o = await t.query(B(L, b(...e, x("concurrencyKey", r.concurrencyKey), E("releasedAt"), C("expiresAt", new Date(i))), [], n.concurrency.limit));
349
- a.inFlight = o.length;
350
- })());
351
- let s = n.rateLimit ?? n.throttle, c = r.rateLimitKey ?? r.throttleKey;
352
- return s !== void 0 && c !== void 0 && o.push((async () => {
353
- let e = await t.query(B(L, b(x("workflowName", n.workflowName), x("rateKey", c), x("outcome", "admitted"), C("admittedAt", new Date(i - s.periodMs))), [{
354
- column: "admittedAt",
355
- direction: "desc"
356
- }], s.limit));
357
- a.recentAdmissions = e.map((e) => R(e.admittedAt));
358
- })()), await Promise.all(o), a;
359
- }, Pe = async (e, t, n, r) => {
360
- let i = (await e.query(B(L, b(x("workflowName", t), x("singletonKey", n), E("releasedAt"), C("expiresAt", new Date(r))), [{
361
- column: "admittedAt",
362
- direction: "desc"
363
- }], 1)))[0];
364
- if (i === void 0) return;
365
- let a = i.executionId;
366
- if (a != null) return {
367
- executionId: String(a),
368
- runId: i.runId === null || i.runId === void 0 ? "" : String(i.runId),
369
- admittedAt: R(i.admittedAt)
370
- };
371
- }, Fe = async (e) => {
372
- let { store: t, control: n, decision: r, now: i } = e, a = Le(r.mode, r.keys);
373
- if (r.collapse === "hold") {
374
- let o = e.existingId ?? Oe(n.workflowName, r.mode, a);
375
- return await t.update(I, o, {
376
- dueAt: new Date(r.dueAt),
377
- updatedAt: new Date(i)
378
- }), o;
379
- }
380
- if (r.collapse === "replace") {
381
- let o = Oe(n.workflowName, r.mode, a);
382
- return await t.upsert(I, {
383
- id: o,
384
- tenantId: e.tenantId,
385
- workflowName: n.workflowName,
386
- controlKey: a,
387
- mode: r.mode,
388
- payload: e.payload,
389
- callerContext: e.callerContext ?? null,
390
- queuedAppVersion: e.queuedAppVersion ?? null,
391
- queuedSchemaFingerprint: e.queuedSchemaFingerprint ?? null,
392
- priority: r.keys.priority,
393
- dueAt: new Date(r.dueAt),
394
- deadlineAt: r.deadlineAt === void 0 ? null : new Date(r.deadlineAt),
395
- collapsed: 1,
396
- firstSeenAt: new Date(i),
397
- updatedAt: new Date(i),
398
- attempts: 0,
399
- lastError: null,
400
- deadLetteredAt: null
401
- }, {
402
- conflictColumns: ["id"],
403
- update: (t) => ({
404
- payload: e.payload,
405
- callerContext: e.callerContext ?? null,
406
- queuedAppVersion: e.queuedAppVersion ?? null,
407
- queuedSchemaFingerprint: e.queuedSchemaFingerprint ?? null,
408
- priority: r.keys.priority,
409
- dueAt: new Date(r.dueAt),
410
- deadlineAt: r.deadlineAt === void 0 ? t.deadlineAt ?? null : new Date(r.deadlineAt),
411
- collapsed: z(t.collapsed, 1) + 1,
412
- updatedAt: new Date(i),
413
- attempts: 0,
414
- lastError: null,
415
- deadLetteredAt: null
416
- })
417
- }), o;
418
- }
419
- let o = await t.insert(I, {
420
- tenantId: e.tenantId,
421
- workflowName: n.workflowName,
422
- controlKey: a,
423
- mode: r.mode,
424
- payload: e.payload,
425
- callerContext: e.callerContext ?? null,
426
- queuedAppVersion: e.queuedAppVersion ?? null,
427
- queuedSchemaFingerprint: e.queuedSchemaFingerprint ?? null,
428
- priority: r.keys.priority,
429
- dueAt: new Date(r.dueAt),
430
- deadlineAt: r.deadlineAt === void 0 ? null : new Date(r.deadlineAt),
431
- collapsed: 1,
432
- firstSeenAt: new Date(i),
433
- updatedAt: new Date(i),
434
- attempts: 0,
435
- lastError: null,
436
- deadLetteredAt: null
437
- });
438
- return String(o.id);
439
- }, Ie = async (e) => {
440
- let t = await e.store.insert(I, {
441
- tenantId: e.tenantId,
442
- workflowName: e.workflowName,
443
- controlKey: "",
444
- mode: "delayed",
445
- payload: e.payload,
446
- callerContext: e.callerContext ?? null,
447
- queuedAppVersion: e.queuedAppVersion ?? null,
448
- queuedSchemaFingerprint: e.queuedSchemaFingerprint ?? null,
449
- priority: 0,
450
- dueAt: new Date(e.at),
451
- deadlineAt: null,
452
- collapsed: 1,
453
- firstSeenAt: new Date(e.now),
454
- updatedAt: new Date(e.now),
455
- attempts: 0,
456
- lastError: null,
457
- deadLetteredAt: null
458
- });
459
- return {
460
- intentId: String(t.id),
461
- dueAt: e.at
462
- };
463
- }, Le = (e, t) => {
464
- switch (e) {
465
- case "debounce": return t.debounceKey ?? "";
466
- case "batch": return t.batchKey ?? "";
467
- case "throttle": return t.throttleKey ?? "";
468
- case "concurrency": return t.concurrencyKey ?? "";
469
- default: return "";
470
- }
471
- }, V = async (e) => {
472
- let { control: t, keys: n, now: r } = e, i = t.timeouts?.finishMs ?? 864e5, a = await e.store.insert(L, {
473
- tenantId: e.tenantId,
474
- workflowName: t.workflowName,
475
- outcome: e.outcome,
476
- mode: e.mode,
477
- reason: e.reason,
478
- collapsed: e.collapsed,
479
- waitedMs: e.waitedMs,
480
- executionId: e.executionId,
481
- runId: e.runId,
482
- singletonKey: n.singletonKey ?? null,
483
- concurrencyKey: n.concurrencyKey ?? null,
484
- rateKey: n.rateLimitKey ?? n.throttleKey ?? null,
485
- admittedAt: new Date(r),
486
- expiresAt: e.outcome === "admitted" ? new Date(r + i) : null,
487
- releasedAt: e.outcome === "admitted" ? null : new Date(r)
488
- });
489
- return String(a.id);
490
- }, Re = async (e, t, n) => {
491
- let r = await e.query(B(L, b(x("executionId", t), x("outcome", "admitted"), E("releasedAt")), [], 10));
492
- return r.length !== 0 && (await Promise.all(r.map((t) => e.update(L, String(t.id), { releasedAt: new Date(n) }))), !0);
493
- }, ze = async (e, t, n) => (await Be(e, t, n)).due, Be = async (e, t, n) => {
494
- let r = (await e.query(B(I, E("deadLetteredAt"), [{
495
- column: "priority",
496
- direction: "desc"
497
- }, {
498
- column: "firstSeenAt",
499
- direction: "asc"
500
- }], n))).map(ke), i;
501
- for (let e of r) e.dueAt <= t || (i === void 0 || e.dueAt < i) && (i = e.dueAt);
502
- return {
503
- due: r.filter((e) => e.dueAt <= t).sort(Te),
504
- nextDueAt: i
505
- };
506
- }, Ve = async (e, t) => (await e.query(B(I, void 0, [{
507
- column: "firstSeenAt",
508
- direction: "asc"
509
- }], t))).map(ke), H = async (e, t) => e.delete(I, t), He = async (e, t, n, r) => {
510
- let i = (await e.query(B(I, x("id", t), [], 1)))[0];
511
- if (i === void 0) return !1;
512
- let a = ke(i);
513
- try {
514
- await e.insert(L, {
515
- tenantId: a.tenantId,
516
- workflowName: a.workflowName,
517
- outcome: "discarded",
518
- mode: a.mode,
519
- reason: n,
520
- collapsed: a.collapsed,
521
- waitedMs: Math.max(0, r - a.firstSeenAt),
522
- executionId: null,
523
- runId: null,
524
- singletonKey: null,
525
- concurrencyKey: a.controlKey === "" ? null : a.controlKey,
526
- rateKey: null,
527
- admittedAt: new Date(r),
528
- expiresAt: null,
529
- releasedAt: new Date(r)
530
- });
531
- } catch {}
532
- return e.delete(I, t);
533
- }, Ue = (e, t = Math.random) => {
534
- let n = Math.min(1e3 * 2 ** Math.max(0, e - 1), 3e5);
535
- return Math.round(n / 2 + t() * (n / 2));
536
- }, U = async (e, t, n, r) => {
537
- let i = t.attempts + 1;
538
- await e.update(I, t.id, {
539
- attempts: i,
540
- lastError: n.slice(0, 500),
541
- dueAt: new Date(r + Ue(i)),
542
- updatedAt: new Date(r)
543
- });
544
- }, We = async (e, t, n, r) => await e.update(I, t.id, {
545
- attempts: t.attempts + 1,
546
- lastError: n.slice(0, 500),
547
- deadLetteredAt: new Date(r),
548
- updatedAt: new Date(r)
549
- }) !== null, Ge = async (e, t, n) => {
550
- let r = (await e.query(B(I, x("id", t), [], 1)))[0];
551
- return r === void 0 || r.deadLetteredAt === null || r.deadLetteredAt === void 0 ? !1 : await e.update(I, t, {
552
- attempts: 0,
553
- lastError: null,
554
- deadLetteredAt: null,
555
- dueAt: new Date(n),
556
- updatedAt: new Date(n)
557
- }) !== null;
558
- }, Ke = async (e) => {
559
- let t = await Ne({
560
- store: e.store,
561
- control: e.control,
562
- keys: e.keys,
563
- now: e.now,
564
- paused: e.paused
565
- });
566
- return xe({
567
- control: e.control,
568
- keys: e.keys,
569
- state: t,
570
- now: e.now,
571
- reconsidering: e.reconsidering
572
- });
573
- }, qe = async (e, t, n = 1e3) => {
574
- let r = await e.query(B(L, void 0, [{
575
- column: "admittedAt",
576
- direction: "asc"
577
- }], n)), i = t.getTime(), a = r.filter((e) => e.releasedAt != null && R(e.admittedAt) < i);
578
- return await Promise.all(a.map((t) => e.delete(L, String(t.id)))), a.length;
579
- }, Je = async (e) => {
580
- let { store: t, control: n, now: r } = e, i = P(n, e.payload), a = await Ke({
581
- store: t,
582
- control: n,
583
- keys: i,
584
- paused: e.paused,
585
- now: r,
586
- reconsidering: !1
587
- });
588
- if (a.kind === "drop") return await V({
589
- store: t,
590
- control: n,
591
- keys: i,
592
- outcome: "dropped",
593
- mode: "rateLimit",
594
- reason: `rate limit reached; retry after ${a.retryAfterMs}ms`,
595
- collapsed: 1,
596
- waitedMs: 0,
597
- executionId: null,
598
- runId: null,
599
- tenantId: e.tenantId,
600
- now: r
601
- }), {
602
- kind: "dropped",
603
- retryAfterMs: a.retryAfterMs
604
- };
605
- if (a.kind === "skip") return await V({
606
- store: t,
607
- control: n,
608
- keys: i,
609
- outcome: "skipped",
610
- mode: "singleton",
611
- reason: `singleton key held by ${a.incumbent.executionId}`,
612
- collapsed: 1,
613
- waitedMs: 0,
614
- executionId: a.incumbent.executionId,
615
- runId: a.incumbent.runId || null,
616
- tenantId: e.tenantId,
617
- now: r
618
- }), {
619
- kind: "skipped",
620
- executionId: a.incumbent.executionId,
621
- runId: a.incumbent.runId
622
- };
623
- if (a.kind === "defer") return {
624
- kind: "queued",
625
- intentId: await Fe({
626
- store: t,
627
- control: n,
628
- decision: a,
629
- payload: e.payload,
630
- callerContext: e.callerContext,
631
- tenantId: e.tenantId,
632
- now: r,
633
- ...e.queuedAppVersion === void 0 ? {} : { queuedAppVersion: e.queuedAppVersion },
634
- ...e.queuedSchemaFingerprint === void 0 ? {} : { queuedSchemaFingerprint: e.queuedSchemaFingerprint }
635
- }),
636
- mode: a.mode,
637
- dueAt: a.dueAt
638
- };
639
- let o = e.payload, s = [], c = 1;
640
- if (n.batch !== void 0 && i.batchKey !== void 0) {
641
- let r = await Ye(t, n.workflowName, i.batchKey, n.batch.maxSize);
642
- o = { items: [...r.map((e) => e.payload), e.payload] }, s = r.map((e) => e.id), c = r.length + 1;
643
- }
644
- return {
645
- kind: "start",
646
- ledgerId: await V({
647
- store: t,
648
- control: n,
649
- keys: i,
650
- outcome: "admitted",
651
- mode: e.waiting ? "immediate" : null,
652
- reason: a.reason,
653
- collapsed: c,
654
- waitedMs: 0,
655
- executionId: null,
656
- runId: null,
657
- tenantId: e.tenantId,
658
- now: r
659
- }),
660
- keys: i,
661
- payload: o,
662
- consume: s,
663
- collapsed: c,
664
- ...a.evict === void 0 ? {} : { evict: {
665
- executionId: a.evict.executionId,
666
- runId: a.evict.runId
667
- } }
668
- };
669
- }, Ye = async (e, t, n, r) => (await e.query({
670
- table: "_voltro_workflow_pending",
671
- predicate: b(x("workflowName", t), x("controlKey", n), x("mode", "batch")),
672
- order: [{
673
- column: "firstSeenAt",
674
- direction: "asc"
675
- }],
676
- take: r,
677
- skip: void 0,
678
- projection: void 0
679
- })).map((e) => ({
680
- id: String(e.id),
681
- payload: e.payload
682
- })), Xe = async (e, t, n, r) => {
683
- await e.update("_voltro_workflow_admissions", t, {
684
- executionId: n,
685
- runId: r
686
- });
687
- }, Ze = A("_voltro_workflow_watermarks", {
688
- id: w({ prefix: "wfwm" }),
689
- positionAt: M(),
690
- updatedAt: M().default("now")
691
- }), Qe = (e) => {
692
- let t = e instanceof Error ? e.message : String(e);
693
- return t.length > 400 ? `${t.slice(0, 400)}…` : t;
694
- }, $e = (e) => {
695
- let t = [], n = [], r = [], i = /* @__PURE__ */ new Set(), a = /* @__PURE__ */ new Set(), o = e.payloadSchema === void 0 ? (e) => h.right(e) : (t) => {
696
- let n = y.decodeUnknownEither(e.payloadSchema)(t);
697
- return h.isRight(n) ? h.right(n.right) : h.left(Qe(n.left));
698
- }, s = e.runs.map((e) => ({
699
- run: e,
700
- decoded: o(e.payload)
701
- })), c = e.intents.map((e) => ({
702
- intent: e,
703
- decoded: o(e.payload)
704
- }));
705
- for (let o of e.entries) for (let l of e.events) {
706
- if (l.name !== o.event) continue;
707
- let u = y.decodeUnknownEither(o.schema)(l.payload);
708
- if (h.isLeft(u)) {
709
- r.push({
710
- kind: "event-decode",
711
- workflowName: e.workflowName,
712
- event: o.event,
713
- subject: l.id,
714
- detail: Qe(u.left)
715
- });
716
- continue;
717
- }
718
- let d = u.right, f = (e) => e.getTime() > l.occurredAt.getTime() ? !1 : o.withinMs === void 0 || l.occurredAt.getTime() - e.getTime() <= o.withinMs, p = (t, n) => {
719
- if (h.isLeft(t)) return r.push({
720
- kind: "payload-decode",
721
- workflowName: e.workflowName,
722
- event: o.event,
723
- subject: n,
724
- detail: t.left
725
- }), !1;
726
- try {
727
- return o.match(d, t.right) === !0;
728
- } catch (t) {
729
- return r.push({
730
- kind: "match-threw",
731
- workflowName: e.workflowName,
732
- event: o.event,
733
- subject: n,
734
- detail: Qe(t)
735
- }), !1;
736
- }
737
- };
738
- for (let { run: e, decoded: n } of s) i.has(e.runId) || f(e.startedAt) && p(n, e.runId) && (i.add(e.runId), t.push({
739
- runId: e.runId,
740
- executionId: e.executionId,
741
- reason: o.reason,
742
- event: o.event,
743
- eventId: l.id
744
- }));
745
- for (let { intent: e, decoded: t } of c) a.has(e.intentId) || f(e.firstSeenAt) && p(t, e.intentId) && (a.add(e.intentId), n.push({
746
- intentId: e.intentId,
747
- reason: o.reason,
748
- event: o.event,
749
- eventId: l.id
750
- }));
751
- }
752
- return {
753
- cancels: t,
754
- discards: n,
755
- problems: r
756
- };
757
- }, et = (e) => {
758
- let t;
759
- for (let n of e) (t === void 0 || n.occurredAt.getTime() > t.getTime()) && (t = n.occurredAt);
760
- return t;
761
- }, tt = "_voltro_workflow_watermarks", nt = "_voltro_workflow_events", W = "cancelOn", rt = 36e5, it = 500, G = (e) => {
762
- if (e instanceof Date) return e;
763
- if (typeof e == "number") return new Date(e);
764
- if (typeof e == "string") {
765
- let t = new Date(e);
766
- if (!Number.isNaN(t.getTime())) return t;
767
- }
768
- }, K = (e) => e instanceof Error ? e.message : String(e), at = async (e, t) => G((await e.query({
769
- table: tt,
770
- predicate: x("id", t),
771
- order: [],
772
- take: 1,
773
- skip: void 0,
774
- projection: void 0
775
- }))[0]?.positionAt), ot = async (e, t, n) => {
776
- await e.upsert(tt, {
777
- id: t,
778
- positionAt: n,
779
- updatedAt: /* @__PURE__ */ new Date()
780
- }, {
781
- conflictColumns: ["id"],
782
- update: (e) => {
783
- let t = G(e.positionAt);
784
- return t !== void 0 && t.getTime() >= n.getTime() ? {
785
- positionAt: t,
786
- updatedAt: /* @__PURE__ */ new Date()
787
- } : {
788
- positionAt: n,
789
- updatedAt: /* @__PURE__ */ new Date()
790
- };
791
- }
792
- });
793
- }, st = async (e, t, n) => {
794
- let r = async (r) => e.query({
795
- table: "_voltro_workflow_runs",
796
- predicate: b(x("tag", t), x("status", r)),
797
- order: [{
798
- column: "startedAt",
799
- direction: "asc"
800
- }],
801
- take: n,
802
- skip: void 0,
803
- projection: void 0
804
- });
805
- return [...await r("running"), ...await r("suspended")].flatMap((e) => {
806
- let t = e, n = G(t.startedAt);
807
- return typeof t.id != "string" || typeof t.executionId != "string" || n === void 0 ? [] : [{
808
- runId: t.id,
809
- executionId: t.executionId,
810
- payload: t.payload,
811
- startedAt: n
812
- }];
813
- });
814
- }, ct = async (e, t, n) => (await e.query({
815
- table: "_voltro_workflow_pending",
816
- predicate: x("workflowName", t),
817
- order: [{
818
- column: "firstSeenAt",
819
- direction: "asc"
820
- }],
821
- take: n,
822
- skip: void 0,
823
- projection: void 0
824
- })).flatMap((e) => {
825
- let t = e, n = G(t.firstSeenAt);
826
- return typeof t.id != "string" || n === void 0 ? [] : [{
827
- intentId: t.id,
828
- payload: t.payload,
829
- firstSeenAt: n
830
- }];
831
- }), lt = async (e, t) => {
832
- let n = t.workflows.filter((e) => e.entries.length > 0);
833
- if (n.length === 0) return {
834
- examined: !1,
835
- events: 0,
836
- cancelled: 0,
837
- discarded: 0,
838
- catchingUp: !1,
839
- sawFullRunPage: !1,
840
- problems: [],
841
- failures: [],
842
- watermark: void 0
843
- };
844
- let r = e.now?.() ?? Date.now(), i = t.batch ?? 500, a = t.coldLookbackMs ?? 36e5, o = /* @__PURE__ */ new Set();
845
- for (let e of n) for (let t of e.entries) o.add(t.event);
846
- let s = await at(e.store, W), c = s ?? new Date(r - a), l = await e.store.query({
847
- table: nt,
848
- predicate: ne("occurredAt", c),
849
- order: [{
850
- column: "occurredAt",
851
- direction: "asc"
852
- }],
853
- take: i,
854
- skip: void 0,
855
- projection: void 0
856
- }), u = [];
857
- for (let e of l) {
858
- let t = e, n = G(t.occurredAt);
859
- typeof t.id == "string" && typeof t.name == "string" && n !== void 0 && o.has(t.name) && u.push({
860
- id: t.id,
861
- name: t.name,
862
- payload: t.payload,
863
- occurredAt: n
864
- });
865
- }
866
- let d = [], f = [], p = 0, m = 0, h = !1, g = !1, _ = t.runPage ?? 2e3;
867
- if (u.length > 0) for (let t of n) {
868
- let n = u.filter((e) => t.entries.some((t) => t.event === e.name));
869
- if (n.length === 0) continue;
870
- let r = [], i = [];
871
- try {
872
- r = await st(e.store, t.workflowName, _), i = await ct(e.store, t.workflowName, _), (r.length >= _ || i.length >= _) && (h = !0);
873
- } catch (e) {
874
- f.push({
875
- subject: t.workflowName,
876
- detail: K(e)
877
- }), g = !0;
878
- continue;
879
- }
880
- let a = $e({
881
- workflowName: t.workflowName,
882
- entries: t.entries,
883
- payloadSchema: t.payloadSchema,
884
- events: n,
885
- runs: r,
886
- intents: i
887
- });
888
- d.push(...a.problems);
889
- for (let n of a.cancels) try {
890
- await e.cancelRun({
891
- workflowName: t.workflowName,
892
- runId: n.runId,
893
- executionId: n.executionId,
894
- reason: n.reason,
895
- event: n.event
896
- }), p += 1, e.log?.info("workflow.cancelOn: run cancelled", {
897
- workflow: t.workflowName,
898
- runId: n.runId,
899
- event: n.event,
900
- eventId: n.eventId
901
- });
902
- } catch (e) {
903
- f.push({
904
- subject: n.runId,
905
- detail: K(e)
906
- });
907
- }
908
- for (let n of a.discards) try {
909
- await e.discardIntent({
910
- workflowName: t.workflowName,
911
- intentId: n.intentId,
912
- reason: n.reason,
913
- event: n.event
914
- }), m += 1;
915
- } catch (e) {
916
- f.push({
917
- subject: n.intentId,
918
- detail: K(e)
919
- });
920
- }
921
- }
922
- let v = et(u), y = s;
923
- if (g) e.log?.warn("workflow.cancelOn: holding the watermark — some workflows could not be evaluated", { failures: f.length });
924
- else if (v !== void 0) try {
925
- await ot(e.store, W, v), y = v;
926
- } catch (e) {
927
- f.push({
928
- subject: W,
929
- detail: K(e)
930
- });
931
- }
932
- else if (s === void 0) try {
933
- await ot(e.store, W, c), y = c;
934
- } catch (e) {
935
- f.push({
936
- subject: W,
937
- detail: K(e)
938
- });
939
- }
940
- return d.length > 0 && e.log?.warn("workflow.cancelOn: some events could not be evaluated", {
941
- count: d.length,
942
- first: d[0]
943
- }), {
944
- examined: !0,
945
- events: u.length,
946
- cancelled: p,
947
- discarded: m,
948
- catchingUp: l.length >= i,
949
- sawFullRunPage: h,
950
- problems: d,
951
- failures: f,
952
- watermark: y
953
- };
954
- }, ut = 18e5, dt = 200, ft = 20, q = (e) => {
955
- if (e instanceof Date) return e;
956
- if (typeof e == "number") return new Date(e);
957
- if (typeof e == "string") {
958
- let t = new Date(e);
959
- if (!Number.isNaN(t.getTime())) return t;
960
- }
961
- }, J = (e) => e instanceof Error ? e.message : String(e), pt = async (e, t, n) => (await e.query({
962
- table: "_voltro_workflow_run_events",
963
- predicate: x("runId", t),
964
- order: [{
965
- column: "occurredAt",
966
- direction: "desc"
967
- }],
968
- take: n,
969
- skip: void 0,
970
- projection: void 0
971
- })).flatMap((e) => {
972
- let t = e, n = q(t.occurredAt);
973
- return typeof t.eventType != "string" || n === void 0 ? [] : [{
974
- eventType: t.eventType,
975
- occurredAt: n,
976
- payload: t.payload
977
- }];
978
- }), mt = async (e, t) => {
979
- let n = (await e.query({
980
- table: "_voltro_workflow_run_steps",
981
- predicate: x("runId", t),
982
- order: [{
983
- column: "startedAt",
984
- direction: "desc"
985
- }],
986
- take: 1,
987
- skip: void 0,
988
- projection: void 0
989
- }))[0];
990
- if (n === void 0) return;
991
- let r = q(n.startedAt), i = q(n.completedAt);
992
- return r === void 0 ? i : i === void 0 ? r : i.getTime() > r.getTime() ? i : r;
993
- }, ht = (e, t) => {
994
- for (let n of e) {
995
- if (n.eventType === "timer-fired") return !1;
996
- if (n.eventType !== "timer-set") continue;
997
- let e = q(n.payload?.scheduledWakeAt);
998
- return e !== void 0 && e.getTime() > t;
999
- }
1000
- return !1;
1001
- }, gt = (e, t) => {
1002
- if (e !== "suspended") return "no-progress";
1003
- for (let e of t) {
1004
- if (e.eventType === "signal-received" || e.eventType === "signal-sent") return "suspended";
1005
- if (e.eventType === "signal-awaited") return "awaiting-signal";
1006
- }
1007
- return "suspended";
1008
- }, _t = async (e, t = {}) => {
1009
- let n = e.now?.() ?? Date.now(), r = t.stallAfterMs ?? 18e5, i = t.runPage ?? 200, a = t.eventLookback ?? 20, o = new Date(n - r), s = [], c = [], l = 0, u = 0, d;
1010
- try {
1011
- d = await e.store.query({
1012
- table: "_voltro_workflow_runs",
1013
- predicate: b(re("status", ["running", "suspended"]), O("startedAt", o)),
1014
- order: [{
1015
- column: "startedAt",
1016
- direction: "asc"
1017
- }],
1018
- take: i,
1019
- skip: void 0,
1020
- projection: void 0
1021
- });
1022
- } catch (e) {
1023
- return {
1024
- examined: 0,
1025
- stalled: [],
1026
- alreadyReported: 0,
1027
- waitingOnTimer: 0,
1028
- sawFullRunPage: !1,
1029
- failures: [{
1030
- subject: "_voltro_workflow_runs",
1031
- detail: J(e)
1032
- }]
1033
- };
1034
- }
1035
- for (let t of d) {
1036
- let i = t, o = q(i.startedAt);
1037
- if (typeof i.id != "string" || typeof i.tag != "string" || typeof i.executionId != "string" || typeof i.status != "string" || o === void 0) continue;
1038
- let d, f;
1039
- try {
1040
- d = await pt(e.store, i.id, a), f = await mt(e.store, i.id);
1041
- } catch (e) {
1042
- s.push({
1043
- subject: i.id,
1044
- detail: J(e)
1045
- });
1046
- continue;
1047
- }
1048
- if (ht(d, n)) {
1049
- u += 1;
1050
- continue;
1051
- }
1052
- let p = d.find((e) => e.eventType !== "run-stalled")?.occurredAt, m = o;
1053
- for (let e of [f, p]) e !== void 0 && e.getTime() > m.getTime() && (m = e);
1054
- let h = n - m.getTime();
1055
- if (h < r) continue;
1056
- if (d.some((e) => e.eventType === "run-stalled" && e.occurredAt.getTime() > m.getTime())) {
1057
- l += 1;
1058
- continue;
1059
- }
1060
- let g = {
1061
- runId: i.id,
1062
- tag: i.tag,
1063
- executionId: i.executionId,
1064
- status: i.status,
1065
- lastProgressAt: m,
1066
- idleMs: h,
1067
- reason: gt(i.status, d)
1068
- };
1069
- c.push(g);
1070
- let _ = {};
1071
- if (e.describeRun !== void 0) try {
1072
- _ = await e.describeRun(g) ?? {};
1073
- } catch (e) {
1074
- s.push({
1075
- subject: `${g.runId}:describeRun`,
1076
- detail: J(e)
1077
- });
1078
- }
1079
- if (e.log?.warn("workflow.staleness: run has made no progress", {
1080
- workflow: g.tag,
1081
- runId: g.runId,
1082
- idleMs: g.idleMs,
1083
- reason: g.reason,
1084
- ..._
1085
- }), e.recordEvent !== void 0) try {
1086
- await e.recordEvent({
1087
- runId: g.runId,
1088
- eventType: "run-stalled",
1089
- payload: {
1090
- idleMs: g.idleMs,
1091
- stallAfterMs: r,
1092
- lastProgressAt: g.lastProgressAt.toISOString(),
1093
- reason: g.reason,
1094
- tag: g.tag,
1095
- executionId: g.executionId,
1096
- ..._
1097
- }
1098
- });
1099
- } catch (e) {
1100
- s.push({
1101
- subject: g.runId,
1102
- detail: J(e)
1103
- });
1104
- }
1105
- if (e.onStalled !== void 0) try {
1106
- await e.onStalled(g);
1107
- } catch (e) {
1108
- s.push({
1109
- subject: `${g.runId}:onStalled`,
1110
- detail: J(e)
1111
- });
1112
- }
1113
- }
1114
- return {
1115
- examined: d.length,
1116
- stalled: c,
1117
- alreadyReported: l,
1118
- waitingOnTimer: u,
1119
- sawFullRunPage: d.length >= i,
1120
- failures: s
1121
- };
1122
- }, vt = {
1123
- scanned: 0,
1124
- admitted: 0,
1125
- deferred: 0,
1126
- dropped: 0,
1127
- skipped: 0,
1128
- expired: 0,
1129
- evicted: 0,
1130
- failed: 0,
1131
- deadLettered: 0,
1132
- timedOut: 0,
1133
- examined: !1
1134
- }, yt = 200, bt = async (e, t = {}) => {
1135
- let n = e.now ?? (() => Date.now()), r = e.log, i = t.batchSize ?? 200, a, o, s;
1136
- try {
1137
- a = await Ae(e.store);
1138
- let t = await Be(e.store, n(), i);
1139
- o = t.due, s = t.nextDueAt;
1140
- } catch (e) {
1141
- return r?.warn?.("workflow flow control: could not read the admission queue", { cause: String(e) }), vt;
1142
- }
1143
- let c = {
1144
- scanned: o.length,
1145
- admitted: 0,
1146
- deferred: 0,
1147
- dropped: 0,
1148
- skipped: 0,
1149
- expired: 0,
1150
- evicted: 0,
1151
- failed: 0,
1152
- deadLettered: 0,
1153
- timedOut: 0
1154
- }, l = /* @__PURE__ */ new Map(), u = [];
1155
- for (let e of o) {
1156
- if (e.mode === "batch") {
1157
- let t = `${e.workflowName}\u0000${e.controlKey}`, n = l.get(t);
1158
- n === void 0 ? l.set(t, [e]) : n.push(e);
1159
- continue;
1160
- }
1161
- u.push(e);
1162
- }
1163
- let d = e.deadLetterAfterAttempts === void 0 ? 50 : e.deadLetterAfterAttempts, f = (t, n, r) => {
1164
- if (e.isPermanentStartError?.(n) === !0) return `pending ${r} was dead-lettered after a permanent start failure: ${String(n)}`;
1165
- if (d !== !1 && t.attempts + 1 >= d) return `pending ${r} was dead-lettered after ${t.attempts + 1} failed attempts: ${String(n)}`;
1166
- };
1167
- for (let t of u) try {
1168
- await xt(e, t, a, c, n());
1169
- } catch (i) {
1170
- c.failed++;
1171
- let a = f(t, i, "intent");
1172
- if (a !== void 0) {
1173
- let o = n(), s = String(i);
1174
- if (!await e.onAbandoned({
1175
- workflowName: t.workflowName,
1176
- payload: t.payload,
1177
- callerContext: t.callerContext,
1178
- reason: a,
1179
- runId: null,
1180
- executionId: null
1181
- }).then(() => !0, (e) => (r?.warn?.("workflow flow control: permanent failure could not signal onFailure", {
1182
- workflow: t.workflowName,
1183
- intent: t.id,
1184
- cause: String(e)
1185
- }), !1))) {
1186
- await U(e.store, t, s, o).catch(() => {});
1187
- continue;
1188
- }
1189
- if (await We(e.store, t, s, o).catch(() => !1)) {
1190
- c.deadLettered++, r?.warn?.("workflow flow control: intent dead-lettered", {
1191
- workflow: t.workflowName,
1192
- intent: t.id,
1193
- cause: s
1194
- });
1195
- continue;
1196
- }
1197
- }
1198
- r?.warn?.("workflow flow control: an intent failed to drain", {
1199
- workflow: t.workflowName,
1200
- intent: t.id,
1201
- cause: String(i)
1202
- }), await U(e.store, t, String(i), n()).catch(() => {});
1203
- }
1204
- for (let t of l.values()) try {
1205
- await Ct(e, t, a, c, n());
1206
- } catch (i) {
1207
- c.failed++;
1208
- let a = t[0], o = a === void 0 ? void 0 : f(a, i, "batch");
1209
- if (a !== void 0 && o !== void 0) {
1210
- let s = n(), l = String(i);
1211
- if (!await e.onAbandoned({
1212
- workflowName: a.workflowName,
1213
- payload: { items: t.map((e) => e.payload) },
1214
- callerContext: a.callerContext,
1215
- reason: o,
1216
- runId: null,
1217
- executionId: null
1218
- }).then(() => !0, (e) => (r?.warn?.("workflow flow control: permanent batch failure could not signal onFailure", {
1219
- workflow: a.workflowName,
1220
- intents: t.map((e) => e.id),
1221
- size: t.length,
1222
- cause: String(e)
1223
- }), !1))) {
1224
- await Promise.all(t.map((t) => U(e.store, t, l, s).catch(() => {})));
1225
- continue;
1226
- }
1227
- if ((await Promise.all(t.map((t) => We(e.store, t, l, s).catch(() => !1)))).every(Boolean)) {
1228
- c.deadLettered += t.length, r?.warn?.("workflow flow control: batch dead-lettered", {
1229
- workflow: a.workflowName,
1230
- intents: t.map((e) => e.id),
1231
- size: t.length,
1232
- cause: l
1233
- });
1234
- continue;
1235
- }
1236
- }
1237
- r?.warn?.("workflow flow control: a batch failed to drain", {
1238
- workflow: a?.workflowName,
1239
- size: t.length,
1240
- cause: String(i)
1241
- }), a !== void 0 && await U(e.store, a, String(i), n()).catch(() => {});
1242
- }
1243
- let p = await Tt(e, n()).catch(() => ({ cancelled: 0 }));
1244
- return c.timedOut = p.cancelled, p.nextDeadlineAt !== void 0 && (s === void 0 || p.nextDeadlineAt < s) && (s = p.nextDeadlineAt), {
1245
- ...c,
1246
- examined: !0,
1247
- ...s === void 0 ? {} : { nextDueAt: s }
1248
- };
1249
- }, xt = async (e, t, n, r, i) => {
1250
- if (t.mode === "delayed") return St(e, t, n, r, i);
1251
- let a = e.controls.get(t.workflowName);
1252
- if (a === void 0) {
1253
- await e.onAbandoned({
1254
- workflowName: t.workflowName,
1255
- payload: t.payload,
1256
- callerContext: t.callerContext,
1257
- reason: `workflow '${t.workflowName}' is no longer registered — it was renamed or removed while this start was waiting in the admission queue`
1258
- }), await H(e.store, t.id), r.expired++;
1259
- return;
1260
- }
1261
- if (Ce(a, t, i)) {
1262
- await V({
1263
- store: e.store,
1264
- control: a,
1265
- keys: P(a, t.payload),
1266
- outcome: "expired",
1267
- mode: t.mode,
1268
- reason: `timeouts.start elapsed after ${i - t.firstSeenAt}ms`,
1269
- collapsed: t.collapsed,
1270
- waitedMs: i - t.firstSeenAt,
1271
- executionId: null,
1272
- runId: null,
1273
- tenantId: t.tenantId,
1274
- now: i
1275
- }), await e.onAbandoned({
1276
- workflowName: t.workflowName,
1277
- payload: t.payload,
1278
- callerContext: t.callerContext,
1279
- reason: `timeouts.start (${a.timeouts?.startMs}ms) elapsed while this start waited in the admission queue; ${t.collapsed} start(s) had collapsed into it`
1280
- }), await H(e.store, t.id), r.expired++;
1281
- return;
1282
- }
1283
- let o = P(a, t.payload);
1284
- await wt(e, {
1285
- control: a,
1286
- intent: t,
1287
- decision: await Ke({
1288
- store: e.store,
1289
- control: a,
1290
- keys: o,
1291
- paused: n.has(t.workflowName),
1292
- now: i,
1293
- reconsidering: !0
1294
- }),
1295
- keys: o,
1296
- counters: r,
1297
- now: i,
1298
- items: void 0
1299
- });
1300
- }, St = async (e, t, n, r, i) => {
1301
- if (e.registeredWorkflows !== void 0 && !e.registeredWorkflows.has(t.workflowName)) {
1302
- await e.onAbandoned({
1303
- workflowName: t.workflowName,
1304
- payload: t.payload,
1305
- callerContext: t.callerContext,
1306
- reason: `workflow '${t.workflowName}' is no longer registered — it was renamed or removed while this delayed start waited for its 'at' instant`
1307
- }), await H(e.store, t.id), r.expired++;
1308
- return;
1309
- }
1310
- let a = e.controls.get(t.workflowName) ?? { workflowName: t.workflowName }, o = await Je({
1311
- store: e.store,
1312
- control: a,
1313
- payload: t.payload,
1314
- callerContext: t.callerContext,
1315
- tenantId: t.tenantId,
1316
- paused: n.has(t.workflowName),
1317
- now: i,
1318
- waiting: !1
1319
- });
1320
- if (o.kind === "queued") {
1321
- await H(e.store, t.id), r.deferred++;
1322
- return;
1323
- }
1324
- if (o.kind === "dropped") {
1325
- await H(e.store, t.id), r.dropped++;
1326
- return;
1327
- }
1328
- if (o.kind === "skipped") {
1329
- await H(e.store, t.id), r.skipped++;
1330
- return;
1331
- }
1332
- let s = await e.startAdmitted(a.workflowName, o.payload, t.callerContext);
1333
- o.evict !== void 0 && (await e.cancelRun({
1334
- workflowName: a.workflowName,
1335
- runId: o.evict.runId,
1336
- executionId: o.evict.executionId,
1337
- reason: "cancelled to make room for a newer start (singleton mode 'cancel')",
1338
- detail: {
1339
- source: "flow-control",
1340
- mode: "singleton"
1341
- }
1342
- }).catch(() => !1), await Re(e.store, o.evict.executionId, i).catch(() => {}), r.evicted++);
1343
- for (let t of o.consume) await H(e.store, t).catch(() => {});
1344
- o.ledgerId !== void 0 && await Xe(e.store, o.ledgerId, s.executionId, s.runId ?? null).catch(() => {}), await H(e.store, t.id), r.admitted++;
1345
- }, Ct = async (e, t, n, r, i) => {
1346
- let a = t[0];
1347
- if (a === void 0) return;
1348
- let o = e.controls.get(a.workflowName);
1349
- if (o === void 0 || o.batch === void 0) {
1350
- for (let n of t) await H(e.store, n.id);
1351
- r.expired += t.length;
1352
- return;
1353
- }
1354
- let s = [...t].sort((e, t) => e.firstSeenAt - t.firstSeenAt), c = s[0];
1355
- if (Ce(o, c, i)) {
1356
- await e.onAbandoned({
1357
- workflowName: a.workflowName,
1358
- payload: { items: s.map((e) => e.payload) },
1359
- callerContext: c.callerContext,
1360
- reason: `timeouts.start elapsed with ${s.length} item(s) accumulated in the batch`
1361
- });
1362
- for (let t of s) await H(e.store, t.id);
1363
- r.expired += s.length;
1364
- return;
1365
- }
1366
- let l = P(o, c.payload);
1367
- await wt(e, {
1368
- control: o,
1369
- intent: c,
1370
- decision: await Ke({
1371
- store: e.store,
1372
- control: o,
1373
- keys: l,
1374
- paused: n.has(a.workflowName),
1375
- now: i,
1376
- reconsidering: !0
1377
- }),
1378
- keys: l,
1379
- counters: r,
1380
- now: i,
1381
- items: s
1382
- });
1383
- }, wt = async (e, t) => {
1384
- let { control: n, intent: r, decision: i, keys: a, counters: o, now: s, items: c } = t;
1385
- if (i.kind === "defer") {
1386
- await Fe({
1387
- store: e.store,
1388
- control: n,
1389
- decision: i,
1390
- payload: r.payload,
1391
- callerContext: r.callerContext,
1392
- tenantId: r.tenantId,
1393
- now: s,
1394
- existingId: r.id
1395
- }), o.deferred++;
1396
- return;
1397
- }
1398
- if (i.kind === "drop") {
1399
- await V({
1400
- store: e.store,
1401
- control: n,
1402
- keys: a,
1403
- outcome: "dropped",
1404
- mode: "rateLimit",
1405
- reason: `rate limit reached while queued; retry after ${i.retryAfterMs}ms`,
1406
- collapsed: r.collapsed,
1407
- waitedMs: s - r.firstSeenAt,
1408
- executionId: null,
1409
- runId: null,
1410
- tenantId: r.tenantId,
1411
- now: s
1412
- });
1413
- for (let t of c ?? [r]) await H(e.store, t.id);
1414
- o.dropped++;
1415
- return;
1416
- }
1417
- if (i.kind === "skip") {
1418
- await V({
1419
- store: e.store,
1420
- control: n,
1421
- keys: a,
1422
- outcome: "skipped",
1423
- mode: "singleton",
1424
- reason: `singleton key held by ${i.incumbent.executionId}`,
1425
- collapsed: r.collapsed,
1426
- waitedMs: s - r.firstSeenAt,
1427
- executionId: i.incumbent.executionId,
1428
- runId: i.incumbent.runId || null,
1429
- tenantId: r.tenantId,
1430
- now: s
1431
- });
1432
- for (let t of c ?? [r]) await H(e.store, t.id);
1433
- o.skipped++;
1434
- return;
1435
- }
1436
- i.evict !== void 0 && (await e.cancelRun({
1437
- workflowName: n.workflowName,
1438
- runId: i.evict.runId,
1439
- executionId: i.evict.executionId,
1440
- reason: "cancelled to make room for a newer start (singleton mode 'cancel')",
1441
- detail: {
1442
- source: "flow-control",
1443
- mode: "singleton"
1444
- }
1445
- }), await Re(e.store, i.evict.executionId, s), await V({
1446
- store: e.store,
1447
- control: n,
1448
- keys: a,
1449
- outcome: "evicted",
1450
- mode: "singleton",
1451
- reason: "cancelled to make room for a newer start (singleton mode 'cancel')",
1452
- collapsed: 1,
1453
- waitedMs: null,
1454
- executionId: i.evict.executionId,
1455
- runId: i.evict.runId || null,
1456
- tenantId: r.tenantId,
1457
- now: s
1458
- }), o.evicted++);
1459
- let l = c === void 0 ? r.payload : { items: c.map((e) => e.payload) }, u = c === void 0 ? r.collapsed : c.reduce((e, t) => e + t.collapsed, 0), d = await e.startAdmitted(n.workflowName, l, r.callerContext);
1460
- await V({
1461
- store: e.store,
1462
- control: n,
1463
- keys: a,
1464
- outcome: "admitted",
1465
- mode: r.mode,
1466
- reason: i.reason,
1467
- collapsed: u,
1468
- waitedMs: s - r.firstSeenAt,
1469
- executionId: d.executionId,
1470
- runId: d.runId ?? null,
1471
- tenantId: r.tenantId,
1472
- now: s
1473
- });
1474
- for (let t of c ?? [r]) await H(e.store, t.id);
1475
- o.admitted++;
1476
- }, Tt = async (e, t) => {
1477
- if (e.listRunningRuns === void 0) return { cancelled: 0 };
1478
- let n = 0, r;
1479
- for (let i of e.controls.values()) {
1480
- if (i.timeouts?.finishMs === void 0) continue;
1481
- let a = await e.listRunningRuns(i.workflowName);
1482
- for (let o of a) {
1483
- if (!we(i, {
1484
- startedAt: o.startedAt,
1485
- terminal: !1
1486
- }, t)) {
1487
- let e = o.startedAt + i.timeouts.finishMs;
1488
- (r === void 0 || e < r) && (r = e);
1489
- continue;
1490
- }
1491
- let a = `timeouts.finish (${i.timeouts.finishMs}ms) elapsed; the run was cancelled after ${t - o.startedAt}ms`;
1492
- await e.cancelRun({
1493
- workflowName: o.workflowName,
1494
- runId: o.runId,
1495
- executionId: o.executionId,
1496
- reason: a,
1497
- detail: {
1498
- source: "flow-control",
1499
- timeout: "finish"
1500
- }
1501
- }) && (await Re(e.store, o.executionId, t), await e.onAbandoned({
1502
- workflowName: o.workflowName,
1503
- payload: o.payload,
1504
- callerContext: null,
1505
- reason: a,
1506
- runId: o.runId,
1507
- executionId: o.executionId
1508
- }), n++);
1509
- }
1510
- }
1511
- return {
1512
- cancelled: n,
1513
- ...r === void 0 ? {} : { nextDeadlineAt: r }
1514
- };
1515
- }, Et = 3e5, Dt, Ot = (e) => {
1516
- Dt = e !== void 0 && Number.isFinite(e) && e > 0 ? e : void 0;
1517
- }, kt = () => {
1518
- let e = process.env.VOLTRO_WORKFLOW_SUSPEND_HINT_MS;
1519
- if (e !== void 0) {
1520
- let t = Number(e);
1521
- if (Number.isFinite(t) && t > 0) return t;
1522
- }
1523
- return Dt ?? 3e5;
1524
- }, At = /* @__PURE__ */ new Set(), jt = () => {
1525
- At.clear();
1526
- }, Mt = (e) => {
1527
- let t = kt();
1528
- if (!(e.timeoutMs > t)) return !1;
1529
- let n = `${e.workflowName ?? ""}\u0000${e.signalName}`;
1530
- if (At.has(n)) return !1;
1531
- At.add(n);
1532
- let r = e.workflowName === void 0 ? "" : ` in workflow '${e.workflowName}'`;
1533
- return (e.warn ?? ((e) => console.warn(e)))(`awaitSignal('${e.signalName}')${r} declares a ${Math.round(e.timeoutMs / 1e3)}s timeout — a wait that long holds a worker fiber for its whole duration. For human-approval-length waits, awaitSignalSuspending (same call shape, from @voltro/workflow) SUSPENDS the run and frees the slot until the signal arrives. This is a hint, not a behaviour change; it is logged once per workflow. Threshold: workflows.suspendSignalHintMs in app.config.ts, or VOLTRO_WORKFLOW_SUSPEND_HINT_MS.`), !0;
1534
- }, Nt = async (e, t) => {
1535
- if (e) try {
1536
- await e.recordEvent(t);
1537
- } catch {}
1538
- }, Pt = (e, t) => {
1539
- let r = m.gen(function* () {
1540
- let r = t.pollIntervalMs ?? 200, i = t.maxPollIntervalMs ?? 5e3, o = t.timeoutMs ?? 864e5, s = yield* m.serviceOption(le), c;
1541
- Mt({
1542
- workflowName: s._tag === "Some" ? s.value.workflow.name : void 0,
1543
- signalName: t.name,
1544
- timeoutMs: o,
1545
- warn: (e) => {
1546
- c = e;
1547
- }
1548
- }), c !== void 0 && (yield* m.logWarning(c));
1549
- let l = yield* a, u = yield* m.serviceOption(n), d = u._tag === "Some" ? u.value : void 0;
1550
- if (l === void 0) return yield* m.die(/* @__PURE__ */ Error("awaitSignal: no active workflow run id in scope"));
1551
- let f = l;
1552
- yield* m.promise(() => Nt(d, {
1553
- runId: f,
1554
- eventType: "signal-awaited",
1555
- payload: { signalName: t.name }
1556
- }));
1557
- let p = Date.now(), h = r;
1558
- for (;;) {
1559
- let n = Date.now() - p;
1560
- if (n > o) return yield* m.die(/* @__PURE__ */ Error(`awaitSignal('${t.name}') timed out after ${n}ms`));
1561
- let r = {
1562
- table: "_voltro_workflow_run_events",
1563
- order: [{
1564
- column: "occurredAt",
1565
- direction: "asc"
1566
- }],
1567
- predicate: b(x("runId", f), x("eventType", "signal-sent")),
1568
- projection: void 0,
1569
- skip: void 0,
1570
- take: 1e3
1571
- }, a = (yield* m.tryPromise({
1572
- try: () => e.store.query(r),
1573
- catch: (e) => e
1574
- })).find((e) => e.payload?.signalName === t.name);
1575
- if (a !== void 0) {
1576
- let e = yield* y.decodeUnknown(t.schema)(a.payload?.value);
1577
- return yield* m.promise(() => Nt(d, {
1578
- runId: f,
1579
- eventType: "signal-received",
1580
- payload: {
1581
- signalName: t.name,
1582
- value: a.payload?.value
1583
- }
1584
- })), e;
1585
- }
1586
- yield* m.sleep(`${h} millis`), h = Math.min(h * 2, i);
1587
- }
1588
- });
1589
- return c.make({
1590
- name: `await-signal:${t.name}`,
1591
- success: t.schema,
1592
- execute: r
1593
- });
1594
- }, Ft = async (e, t) => {
1595
- if (e !== void 0) try {
1596
- await e.recordEvent(t);
1597
- } catch {}
1598
- }, It = (e, t) => {
1599
- let r = m.gen(function* () {
1600
- let r = t.pollIntervalMs ?? 200, i = t.maxPollIntervalMs ?? 5e3, o = t.timeoutMs ?? 864e5, s = t.take ?? 500, c = yield* a, l = yield* m.serviceOption(n), u = l._tag === "Some" ? l.value : void 0;
1601
- if (c === void 0) return yield* m.die(/* @__PURE__ */ Error("awaitEvent: no active workflow run id in scope"));
1602
- let d = c, f = yield* t.since === "run-start" ? Lt(e, d) : m.succeed(/* @__PURE__ */ new Date());
1603
- yield* m.promise(() => Ft(u, {
1604
- runId: d,
1605
- eventType: "event-awaited",
1606
- payload: {
1607
- event: t.event,
1608
- since: t.since ?? "wait-start",
1609
- cutoff: f.toISOString()
1610
- }
1611
- }));
1612
- let p = Date.now(), h = r, g = 0;
1613
- for (;;) {
1614
- let n = Date.now() - p;
1615
- if (n > o) return yield* m.die(/* @__PURE__ */ Error(`awaitEvent('${t.event}') timed out after ${n}ms having examined ${g} candidate event(s). ${g === 0 ? "NONE were published under that name in the window — check the spelling against ctx.events.publish, and consider since: 'run-start' if the event may have arrived before this step began." : "The predicate rejected all of them — log one payload and compare it with what `match` expects."}`));
1616
- let r = {
1617
- table: "_voltro_workflow_events",
1618
- predicate: b(x("name", t.event), ne("occurredAt", f)),
1619
- order: [{
1620
- column: "occurredAt",
1621
- direction: "asc"
1622
- }],
1623
- take: s,
1624
- skip: void 0,
1625
- projection: void 0
1626
- }, a = yield* m.tryPromise({
1627
- try: () => e.store.query(r),
1628
- catch: (e) => e
1629
- });
1630
- g = a.length;
1631
- for (let e of a) {
1632
- let n = yield* y.decodeUnknown(t.schema)(e.payload);
1633
- if (t.match(n)) return yield* m.promise(() => Ft(u, {
1634
- runId: d,
1635
- eventType: "event-received",
1636
- payload: {
1637
- event: t.event,
1638
- eventId: e.id
1639
- }
1640
- })), n;
1641
- }
1642
- yield* m.sleep(`${h} millis`), h = Math.min(h * 2, i);
1643
- }
1644
- });
1645
- return c.make({
1646
- name: `awaitEvent:${t.event}`,
1647
- success: t.schema,
1648
- execute: r
1649
- });
1650
- }, Lt = (e, t) => m.gen(function* () {
1651
- let n = (yield* m.tryPromise({
1652
- try: () => e.store.query({
1653
- table: "_voltro_workflow_runs",
1654
- predicate: x("id", t),
1655
- order: [],
1656
- take: 1,
1657
- skip: void 0,
1658
- projection: void 0
1659
- }),
1660
- catch: (e) => e
1661
- }))[0]?.startedAt;
1662
- if (n instanceof Date) return n;
1663
- if (typeof n == "string" || typeof n == "number") {
1664
- let e = new Date(n);
1665
- if (!Number.isNaN(e.getTime())) return e;
1666
- }
1667
- return /* @__PURE__ */ new Date(0);
1668
- }), Rt = (e) => new Promise((t) => setTimeout(t, e)), zt = () => {
1669
- let e = globalThis.crypto;
1670
- return typeof e?.randomUUID == "function" ? e.randomUUID() : `${Date.now().toString(36)}${Math.random().toString(36).slice(2)}`;
1671
- }, Bt = () => `wfu_${zt()}`, Vt = async (e, t) => {
1672
- let n = t.id ?? t.executionId;
1673
- if (!n) throw Error("workflow message target requires target.id or target.executionId");
1674
- let r = await e.query({
1675
- table: "_voltro_workflow_runs",
1676
- order: [],
1677
- predicate: x("id", n),
1678
- projection: void 0,
1679
- skip: void 0,
1680
- take: 1
1681
- });
1682
- if (r[0]) return r[0];
1683
- let i = (await e.query({
1684
- table: "_voltro_workflow_runs",
1685
- order: [],
1686
- predicate: x("executionId", n),
1687
- projection: void 0,
1688
- skip: void 0,
1689
- take: 1
1690
- }))[0];
1691
- if (!i) throw Error(`workflow message target not found: ${n}`);
1692
- return i;
1693
- }, Ht = async (e) => {
1694
- let t = await Vt(e.store, e.target);
1695
- return { eventId: (await e.recorder.recordEvent({
1696
- runId: t.id,
1697
- eventType: "signal-sent",
1698
- payload: {
1699
- signalName: e.signalName,
1700
- value: e.payload
1701
- }
1702
- })).id };
1703
- }, Ut = async (e) => {
1704
- let t = await Vt(e.store, e.target), n = Bt(), r = await e.recorder.recordEvent({
1705
- runId: t.id,
1706
- eventType: "update-requested",
1707
- payload: {
1708
- updateId: n,
1709
- updateName: e.updateName,
1710
- value: e.payload
1711
- }
1712
- }), i = Date.now(), a = e.options?.timeoutMs ?? 3e4, o = e.options?.pollIntervalMs ?? 100;
1713
- for (;;) {
1714
- let s = {
1715
- table: "_voltro_workflow_run_events",
1716
- order: [{
1717
- column: "occurredAt",
1718
- direction: "asc"
1719
- }],
1720
- predicate: x("runId", t.id),
1721
- projection: void 0,
1722
- skip: void 0,
1723
- take: 1e3
1724
- }, c = await e.store.query(s), l = c.find((e) => e.eventType === "update-completed" && e.payload?.updateId === n);
1725
- if (l) return {
1726
- eventId: r.id,
1727
- updateId: n,
1728
- completedEventId: l.id,
1729
- result: l.payload?.result
1730
- };
1731
- let u = c.find((e) => e.eventType === "update-failed" && e.payload?.updateId === n);
1732
- if (u) {
1733
- let t = Error(u.payload?.errorMessage ?? `workflow update '${e.updateName}' failed`);
1734
- throw Object.assign(t, {
1735
- updateId: n,
1736
- eventId: r.id,
1737
- errorTag: u.payload?.errorTag ?? null
1738
- }), t;
1739
- }
1740
- if (Date.now() - i >= a) throw Error(`Timed out waiting for workflow update '${e.updateName}' (${n})`);
1741
- await Rt(o);
1742
- }
1743
- }, Wt = 864e5, Gt = "voltro/suspending-signal", Kt = (e, t) => `${Gt}/${e}/${t}`, qt = (e) => u.make(e, { success: y.Unknown }), Jt = async (e, t) => {
1744
- if (e) try {
1745
- await e.recordEvent(t);
1746
- } catch {}
1747
- }, Yt = (e, t) => m.gen(function* () {
1748
- let e = t.timeoutMs ?? Wt, r = qt(Kt((yield* f.WorkflowInstance).workflow.name, t.name)), i = yield* a, o = yield* m.serviceOption(n), s = o._tag === "Some" ? o.value : void 0;
1749
- i !== void 0 && (yield* m.promise(() => Jt(s, {
1750
- runId: i,
1751
- eventType: "signal-awaited",
1752
- payload: { signalName: t.name }
1753
- })));
1754
- let c = u.await(r), d = Number.isFinite(e) ? yield* m.race(c, l.sleep({
1755
- name: `await-signal-timeout/${t.name}`,
1756
- duration: `${e} millis`
1757
- }).pipe(m.andThen(m.die(/* @__PURE__ */ Error(`awaitSignalSuspending('${t.name}') timed out after ${e}ms`))))) : yield* c, p = yield* y.decodeUnknown(t.schema)(d);
1758
- return i !== void 0 && (yield* m.promise(() => Jt(s, {
1759
- runId: i,
1760
- eventType: "signal-received",
1761
- payload: {
1762
- signalName: t.name,
1763
- value: p
1764
- }
1765
- }))), p;
1766
- }), Xt = (e) => m.gen(function* () {
1767
- let t = e.target.executionId, n = e.target.workflowName;
1768
- if (t === void 0 || n === void 0) {
1769
- let r = e.store;
1770
- if (r === void 0) return yield* m.die(/* @__PURE__ */ Error("completeSuspendingSignal: provide a store, or target.executionId AND target.workflowName"));
1771
- let i = yield* m.tryPromise({
1772
- try: () => Vt(r, e.target),
1773
- catch: (e) => e
1774
- });
1775
- t ??= i.executionId, n ??= i.tag;
1776
- }
1777
- if (t === void 0 || n === void 0) return { completed: !1 };
1778
- let r = Kt(n, e.signalName), i = qt(r), a = new u.TokenParsed({
1779
- workflowName: n,
1780
- executionId: t,
1781
- deferredName: r
1782
- }).asToken;
1783
- return yield* u.done(i, {
1784
- token: a,
1785
- exit: g.succeed(e.payload)
1786
- }), { completed: !0 };
1787
- }), Y = "_voltro_budget_holds", Zt = "budget-hold", Qt = (e) => `${Zt}:${e}`, $t = (e) => `${e.executionId}/${e.stepName}/${e.budget}#${e.generation}`, en = async (e, t) => (await e.query({
1788
- table: Y,
1789
- predicate: b(x("executionId", t.executionId), x("stepName", t.stepName), x("budget", t.budget)),
1790
- order: []
1791
- })).length, tn = A(Y, {
1792
- id: w({ prefix: "bhd" }),
1793
- holdKey: j().maxLength(191),
1794
- budget: j(),
1795
- tenantId: j().nullable(),
1796
- executionId: j(),
1797
- workflowName: j(),
1798
- signalName: j(),
1799
- stepName: j(),
1800
- spentMicroUsd: j().nullable(),
1801
- limitMicroUsd: j().nullable(),
1802
- heldAt: M().default("now"),
1803
- releasedAt: M().nullable(),
1804
- outcome: j().nullable()
1805
- }).index(["budget", "releasedAt"]), nn = () => {
1806
- oe({
1807
- source: "framework",
1808
- table: Y,
1809
- timeColumn: "releasedAt",
1810
- ttlMs: se(process.env.VOLTRO_BUDGET_HOLDS_TTL_HOURS, 720)
1811
- });
1812
- }, rn = class extends Error {
1813
- budget;
1814
- holdKey;
1815
- constructor(e, t, n) {
1816
- super(`budget '${e}': the run was suspended waiting for headroom and gave up after ${n}ms (hold ${t}). Nothing was spent. Raise the budget, reset its window, or lift the hold, then re-drive the run.`), this.name = "BudgetHoldExpired", this.budget = e, this.holdKey = t;
1817
- }
1818
- }, an = 6048e5, on = (e) => m.gen(function* () {
1819
- nn();
1820
- let t = e.timeoutMs ?? 6048e5, n = e.recheckEveryMs ?? 9e5, r = {
1821
- executionId: e.executionId,
1822
- stepName: e.stepName,
1823
- budget: e.budget
1824
- };
1825
- for (;;) {
1826
- let i = yield* m.promise(() => cn(e.store, r)), a = i.length, o = i.length === 0 ? Date.now() : sn(i[0]?.heldAt), s = Number.isFinite(t) ? t - (Date.now() - o) : Infinity, c = $t({
1827
- ...r,
1828
- generation: a
1829
- });
1830
- if (s <= 0) return yield* m.promise(() => ln(e.store, r, "expired")), yield* m.fail(new rn(e.budget, c, t));
1831
- let l = Qt(c);
1832
- yield* m.promise(() => e.store.insertIgnore(Y, {
1833
- id: S({
1834
- kind: "typeid",
1835
- prefix: "bhd"
1836
- }, Y),
1837
- holdKey: c,
1838
- budget: e.budget,
1839
- tenantId: e.tenantId,
1840
- executionId: e.executionId,
1841
- workflowName: e.workflowName,
1842
- signalName: l,
1843
- stepName: e.stepName,
1844
- spentMicroUsd: e.spentMicroUsd === void 0 ? null : String(Math.round(e.spentMicroUsd)),
1845
- limitMicroUsd: e.limitMicroUsd === void 0 ? null : String(Math.round(e.limitMicroUsd)),
1846
- heldAt: /* @__PURE__ */ new Date(),
1847
- releasedAt: null,
1848
- outcome: null
1849
- }, { conflictColumns: ["holdKey"] }));
1850
- let u = Math.min(n, s);
1851
- if (yield* Yt({ store: e.store }, {
1852
- name: l,
1853
- schema: y.Unknown,
1854
- timeoutMs: u
1855
- }).pipe(m.catchAllCause((e) => p.isInterruptedOnly(e) ? m.failCause(e) : m.void)), yield* m.promise(() => e.store.updateMany(Y, {
1856
- releasedAt: /* @__PURE__ */ new Date(),
1857
- outcome: "recheck"
1858
- }, { where: b(x("holdKey", c), E("releasedAt")) })), yield* e.hasHeadroom) return;
1859
- }
1860
- }), sn = (e) => e instanceof Date ? e.getTime() : typeof e == "string" ? Date.parse(e) : Date.now(), cn = async (e, t) => [...await e.query({
1861
- table: Y,
1862
- predicate: b(x("executionId", t.executionId), x("stepName", t.stepName), x("budget", t.budget)),
1863
- order: []
1864
- })].sort((e, t) => String(e.id).localeCompare(String(t.id))), ln = async (e, t, n) => {
1865
- await e.updateMany(Y, {
1866
- releasedAt: /* @__PURE__ */ new Date(),
1867
- outcome: n
1868
- }, { where: b(x("executionId", t.executionId), x("stepName", t.stepName), x("budget", t.budget), E("releasedAt")) });
1869
- }, un = (e) => m.gen(function* () {
1870
- let t = e.tenantId === void 0 ? b(x("budget", e.budget), E("releasedAt")) : b(x("budget", e.budget), x("tenantId", e.tenantId), E("releasedAt")), n = yield* m.promise(() => e.store.query({
1871
- table: Y,
1872
- predicate: t,
1873
- order: []
1874
- })), r = 0;
1875
- for (let t of n) (yield* m.promise(() => e.store.updateMany("_voltro_budget_holds", {
1876
- releasedAt: /* @__PURE__ */ new Date(),
1877
- outcome: e.outcome ?? "released"
1878
- }, { where: b(x("id", String(t.id)), E("releasedAt")) }))) === 1 && (yield* Xt({
1879
- target: {
1880
- executionId: String(t.executionId),
1881
- workflowName: String(t.workflowName)
1882
- },
1883
- signalName: String(t.signalName),
1884
- payload: {
1885
- released: !0,
1886
- budget: e.budget
1887
- }
1888
- }).pipe(m.catchAll(() => m.succeed({ completed: !1 }))), r += 1);
1889
- return { released: r };
1890
- }), dn = async (e, t) => {
1891
- let n = t?.budget === void 0 ? E("releasedAt") : b(x("budget", t.budget), E("releasedAt"));
1892
- return (await e.query({
1893
- table: Y,
1894
- predicate: n,
1895
- order: []
1896
- })).map((e) => ({
1897
- id: String(e.id),
1898
- holdKey: String(e.holdKey),
1899
- budget: String(e.budget),
1900
- tenantId: e.tenantId ?? null,
1901
- executionId: String(e.executionId),
1902
- workflowName: String(e.workflowName),
1903
- stepName: String(e.stepName),
1904
- heldAt: e.heldAt instanceof Date ? e.heldAt.toISOString() : String(e.heldAt ?? "")
1905
- }));
1906
- }, fn = async (e) => {
1907
- let t = await dn(e), n = /* @__PURE__ */ new Map();
1908
- for (let e of t) {
1909
- let t = `${e.budget}\u0000${e.tenantId ?? ""}`;
1910
- n.has(t) || n.set(t, {
1911
- budget: e.budget,
1912
- tenantId: e.tenantId
1913
- });
1914
- }
1915
- return [...n.values()];
1916
- }, pn = async (e, t) => {
1917
- if (e) try {
1918
- await e.recordEvent(t);
1919
- } catch {}
1920
- }, mn = (e) => {
1921
- let t = p.failureOption(e), n = Array.from(p.defects(e)), r = t._tag === "Some" ? t.value : n[0] ?? p.squash(e);
1922
- return {
1923
- errorTag: r && typeof r == "object" && "_tag" in r ? String(r._tag) : null,
1924
- errorMessage: r?.message ?? String(r)
1925
- };
1926
- }, hn = (e, t) => {
1927
- let r = m.gen(function* () {
1928
- let r = t.pollIntervalMs ?? 200, i = t.maxPollIntervalMs ?? 5e3, o = t.timeoutMs ?? 3e4, s = yield* a, c = yield* m.serviceOption(n), l = c._tag === "Some" ? c.value : void 0;
1929
- if (s === void 0) return yield* m.die(/* @__PURE__ */ Error("awaitUpdate: no active workflow run id in scope"));
1930
- let u = s, d = Date.now(), f = r;
1931
- for (;;) {
1932
- let n = Date.now() - d;
1933
- if (n > o) return yield* m.die(/* @__PURE__ */ Error(`awaitUpdate('${t.name}') timed out after ${n}ms`));
1934
- let r = {
1935
- table: "_voltro_workflow_run_events",
1936
- order: [{
1937
- column: "occurredAt",
1938
- direction: "asc"
1939
- }],
1940
- predicate: x("runId", u),
1941
- projection: void 0,
1942
- skip: void 0,
1943
- take: 1e3
1944
- }, a = yield* m.tryPromise({
1945
- try: () => e.store.query(r),
1946
- catch: (e) => e
1947
- }), s = new Set(a.filter((e) => e.eventType === "update-completed" || e.eventType === "update-failed").map((e) => e.payload?.updateId).filter((e) => typeof e == "string" && e.length > 0)), c = a.find((e) => e.eventType === "update-requested" && e.payload?.updateName === t.name && typeof e.payload.updateId == "string" && !s.has(e.payload.updateId));
1948
- if (c !== void 0) {
1949
- let e = c.payload.updateId;
1950
- yield* m.promise(() => pn(l, {
1951
- runId: u,
1952
- eventType: "update-received",
1953
- payload: {
1954
- updateId: e,
1955
- updateName: t.name
1956
- }
1957
- }));
1958
- let n = yield* y.decodeUnknown(t.schema)(c.payload?.value).pipe(m.tapErrorCause((n) => m.promise(() => pn(l, {
1959
- runId: u,
1960
- eventType: "update-failed",
1961
- payload: {
1962
- updateId: e,
1963
- updateName: t.name,
1964
- ...mn(n)
1965
- }
1966
- })))), r = yield* (t.handle ? t.handle(n) : m.succeed(n)).pipe(m.flatMap((e) => t.success ? y.decodeUnknown(t.success)(e) : m.succeed(e))).pipe(m.tapErrorCause((n) => m.promise(() => pn(l, {
1967
- runId: u,
1968
- eventType: "update-failed",
1969
- payload: {
1970
- updateId: e,
1971
- updateName: t.name,
1972
- ...mn(n)
1973
- }
1974
- }))));
1975
- return yield* m.promise(() => pn(l, {
1976
- runId: u,
1977
- eventType: "update-completed",
1978
- payload: {
1979
- updateId: e,
1980
- updateName: t.name,
1981
- result: r
1982
- }
1983
- })), r;
1984
- }
1985
- yield* m.sleep(`${f} millis`), f = Math.min(f * 2, i);
1986
- }
1987
- });
1988
- return c.make({
1989
- name: `await-update:${t.name}`,
1990
- success: t.success ?? t.schema,
1991
- execute: r
1992
- });
1993
- }, gn = 8192, _n = 3, vn = 2e3, yn = () => {
1994
- let e = (e) => {
1995
- if (e === void 0) return;
1996
- let t = Number(e);
1997
- return Number.isFinite(t) && t > 0 ? Math.floor(t) : void 0;
1998
- }, t = e(process.env.VOLTRO_WORKFLOW_MAX_RECLAIMS), n = e(process.env.VOLTRO_WORKFLOW_REPLAY_SHAPE_LIMIT);
1999
- return {
2000
- ...t === void 0 ? {} : { maxRunReclaims: t },
2001
- ...n === void 0 ? {} : { replayShapeLimit: n }
2002
- };
2003
- }, bn = (e) => {
2004
- let t = typeof e == "string" ? (() => {
2005
- try {
2006
- return JSON.parse(e);
2007
- } catch {
2008
- return;
2009
- }
2010
- })() : e;
2011
- if (Array.isArray(t)) return t.filter((e) => typeof e == "string");
2012
- }, xn = () => {
2013
- let e = globalThis.crypto;
2014
- return typeof e?.randomUUID == "function" ? e.randomUUID() : `${Date.now().toString(36)}${Math.random().toString(36).slice(2)}`;
2015
- }, Sn = (e) => `${e}_${xn()}`, X = (e, t = gn) => {
2016
- if (e == null) return e;
2017
- try {
2018
- let n = JSON.stringify(e);
2019
- return n.length <= t ? e : {
2020
- __truncated: !0,
2021
- bytes: n.length,
2022
- sample: n.slice(0, t)
2023
- };
2024
- } catch {
2025
- return { __unserialisable: String(e) };
2026
- }
2027
- }, Z = (e) => {
2028
- let t = {};
2029
- for (let [n, r] of Object.entries(e)) t[n] = r instanceof Date ? r.toISOString() : r;
2030
- return t;
2031
- }, Cn = (e) => {
2032
- let t = e.truncateBytes ?? gn, n = e.makeId ?? Sn, r = (t, n) => e.log?.warn(t, n), i = e.encryptStepPayload ?? ((e) => e), a = e.emit, o = e.recording === "coarse";
2033
- return {
2034
- startStep: async ({ runId: s, stepName: c, attempt: l, stepInput: u, retryPolicy: d }) => {
2035
- if (!o) try {
2036
- let r = await e.store.insert("_voltro_workflow_run_steps", {
2037
- id: n("ws"),
2038
- runId: s,
2039
- stepName: c,
2040
- attempt: l,
2041
- status: "running",
2042
- input: u === void 0 ? null : i(X(u, t)),
2043
- retryPolicy: d ?? null,
2044
- output: null,
2045
- errorTag: null,
2046
- errorMessage: null,
2047
- startedAt: /* @__PURE__ */ new Date(),
2048
- completedAt: null,
2049
- durationMs: null
2050
- });
2051
- return a?.("workflowSteps", {
2052
- op: "insert",
2053
- row: Z(r)
2054
- }), r.id;
2055
- } catch (e) {
2056
- r("failed to record step start (continuing)", {
2057
- runId: s,
2058
- stepName: c,
2059
- attempt: l,
2060
- reason: e?.message ?? String(e)
2061
- });
2062
- return;
2063
- }
2064
- },
2065
- endStepSuccess: async ({ stepRecordId: n, output: s, durationMs: c }) => {
2066
- if (!o) try {
2067
- let r = await e.store.update("_voltro_workflow_run_steps", n, {
2068
- status: "succeeded",
2069
- output: i(X(s, t)),
2070
- completedAt: /* @__PURE__ */ new Date(),
2071
- durationMs: c
2072
- });
2073
- r && a?.("workflowSteps", {
2074
- op: "update",
2075
- row: Z(r)
2076
- });
2077
- } catch (e) {
2078
- r("failed to record step success", {
2079
- stepRecordId: n,
2080
- reason: e?.message ?? String(e)
2081
- });
2082
- }
2083
- },
2084
- endStepFailure: async ({ stepRecordId: n, errorTag: s, errorMessage: c, errorCause: l, durationMs: u }) => {
2085
- if (!o) try {
2086
- let r = await e.store.update("_voltro_workflow_run_steps", n, {
2087
- status: "failed",
2088
- errorTag: s,
2089
- errorMessage: c,
2090
- errorCause: l === void 0 ? null : i(X(l, t)),
2091
- completedAt: /* @__PURE__ */ new Date(),
2092
- durationMs: u
2093
- });
2094
- r && a?.("workflowSteps", {
2095
- op: "update",
2096
- row: Z(r)
2097
- });
2098
- } catch (e) {
2099
- r("failed to record step failure", {
2100
- stepRecordId: n,
2101
- reason: e?.message ?? String(e)
2102
- });
2103
- }
2104
- },
2105
- recordEvent: async ({ runId: t, eventType: i, payload: o, stepName: s, attempt: c }) => {
2106
- let l = n("wfev");
2107
- try {
2108
- let n = await e.store.insert("_voltro_workflow_run_events", {
2109
- id: l,
2110
- runId: t,
2111
- eventType: i,
2112
- payload: o ?? null,
2113
- occurredAt: /* @__PURE__ */ new Date(),
2114
- stepName: s ?? null,
2115
- attempt: c ?? null
2116
- });
2117
- a?.("workflowEvents", {
2118
- op: "insert",
2119
- row: Z(n)
2120
- });
2121
- } catch (e) {
2122
- r("failed to record workflow event (continuing)", {
2123
- runId: t,
2124
- eventType: i,
2125
- reason: e?.message ?? String(e)
2126
- });
2127
- }
2128
- if (e.wakeups !== void 0) {
2129
- let n = o?.scheduledWakeAt, r = typeof n == "string" ? new Date(n) : void 0, a = o?.tenantId, s = typeof a == "string" ? a : void 0;
2130
- i === "timer-set" && r !== void 0 && !Number.isNaN(r.getTime()) ? await e.wakeups.register(t, r, s).catch(() => {}) : (i === "timer-fired" || i === "run-succeeded" || i === "run-failed" || i === "run-cancelled") && await e.wakeups.cancel(t, s).catch(() => {});
2131
- }
2132
- return { id: l };
2133
- }
2134
- };
2135
- }, wn = (e, t, n) => m.gen(function* () {
2136
- let r = e.store.query;
2137
- if (r === void 0) return;
2138
- let i = e.replayShapeLimit ?? 2e3, a = yield* m.promise(() => r({
2139
- table: "_voltro_workflow_run_steps",
2140
- order: [{
2141
- column: "startedAt",
2142
- direction: "asc"
2143
- }],
2144
- predicate: x("runId", t),
2145
- projection: ["stepName"],
2146
- skip: void 0,
2147
- take: i + 1
2148
- }).catch((e) => (n("failed to read the replay shape (nondeterminism tripwire disabled for this attempt)", {
2149
- runId: t,
2150
- reason: e?.message ?? String(e)
2151
- }), [])));
2152
- if (a.length === 0) return;
2153
- if (a.length > i) {
2154
- n("replay shape exceeds the step limit — nondeterminism tripwire disabled for this run", {
2155
- runId: t,
2156
- limit: i
2157
- });
2158
- return;
2159
- }
2160
- let s = a.flatMap((e) => {
2161
- let t = e.stepName;
2162
- return typeof t == "string" ? [{ stepName: t }] : [];
2163
- });
2164
- return s.length === 0 ? void 0 : o(s);
2165
- }), Tn = (o, c) => {
2166
- let l = o.truncateBytes ?? gn, u = o.makeId ?? Sn, f = o.recorder ?? Cn(o), h = (e, t) => o.log?.warn(e, t), v = o.emit, y = (e, t, n) => m.promise(async () => {
2167
- if (o.onParentClose) try {
2168
- await o.onParentClose({
2169
- workflowName: o.name,
2170
- executionId: e,
2171
- ...n === void 0 ? {} : { runId: n },
2172
- status: t
2173
- });
2174
- } catch (n) {
2175
- h("failed to apply workflow parent-close policy", {
2176
- tag: o.name,
2177
- executionId: e,
2178
- status: t,
2179
- reason: n?.message ?? String(n)
2180
- });
2181
- }
2182
- }), b = (e, t, n, r) => m.promise(async () => {
2183
- if (o.onTerminal) try {
2184
- await o.onTerminal({
2185
- workflowName: o.name,
2186
- executionId: e,
2187
- ...n === void 0 ? {} : { runId: n },
2188
- status: t,
2189
- ...r === void 0 ? {} : r
2190
- });
2191
- } catch (n) {
2192
- h("failed to release the workflow admission lease", {
2193
- tag: o.name,
2194
- executionId: e,
2195
- status: t,
2196
- reason: n?.message ?? String(n)
2197
- });
2198
- }
2199
- });
2200
- return (te, S) => m.gen(function* () {
2201
- let C = Date.now(), ne = yield* _.get(r), w = o.parentExecutionId ?? ne ?? null, re = o.parentClosePolicy ?? null, T, E = (e, t) => t.pipe(m.catchAllCause((t) => p.isInterrupted(t) ? m.failCause(t) : m.sync(() => {
2202
- let n = p.squash(t);
2203
- h(e, {
2204
- tag: o.name,
2205
- executionId: S,
2206
- reason: n?.message ?? String(n)
2207
- });
2208
- }))), D = (o.store.query ? yield* m.promise(() => o.store.query({
2209
- table: "_voltro_workflow_runs",
2210
- order: [],
2211
- predicate: x("executionId", S),
2212
- projection: void 0,
2213
- skip: void 0,
2214
- take: 1
2215
- })) : [])[0], O = D?.workflowVersion ?? null;
2216
- if (D?.id !== void 0 && O !== null && o.workflowCompatibleVersions !== void 0 && o.workflowCompatibleVersions !== null && !o.workflowCompatibleVersions.includes(O)) {
2217
- let e = `Workflow '${o.name}' run '${S}' was started on version ${O}, but current code is compatible with ${o.workflowCompatibleVersions.join(", ")}`, t = yield* m.promise(() => o.store.update("_voltro_workflow_runs", D.id, {
2218
- status: "failed",
2219
- errorTag: "WorkflowVersionIncompatible",
2220
- errorMessage: e,
2221
- completedAt: /* @__PURE__ */ new Date(),
2222
- runnerEnteredAt: null
2223
- }));
2224
- return t && v?.("workflowRuns", {
2225
- op: "update",
2226
- row: Z(t)
2227
- }), yield* m.promise(() => f.recordEvent({
2228
- runId: D.id,
2229
- eventType: "run-failed",
2230
- payload: {
2231
- errorTag: "WorkflowVersionIncompatible",
2232
- errorMessage: e,
2233
- workflowVersion: o.workflowVersion ?? null,
2234
- compatibleWith: o.workflowCompatibleVersions,
2235
- previousVersion: O
2236
- }
2237
- })), yield* m.sync(() => o.recordRun?.({
2238
- name: o.name,
2239
- status: "failed",
2240
- durationMs: 0
2241
- })), yield* m.fail(Error(e));
2242
- }
2243
- let ie = o.workflowPatches ?? [], k;
2244
- if (D?.id !== void 0) {
2245
- T = D.id, ie = bn(D.workflowPatches) ?? ie;
2246
- let e = D.runnerEnteredAt !== null && D.runnerEnteredAt !== void 0, t = typeof D.reclaimCount == "number" ? D.reclaimCount : Number(D.reclaimCount ?? 0), n = e ? (Number.isFinite(t) ? t : 0) + 1 : 0, r = o.maxRunReclaims ?? 3;
2247
- if (e && n >= r) {
2248
- let e = `Workflow '${o.name}' run '${S}' killed its runner ${n} times in a row; parked instead of reclaimed again (maxRunReclaims=${r}).`;
2249
- yield* E("failed to record workflow crash-loop park", m.gen(function* () {
2250
- let t = yield* m.promise(() => o.store.update("_voltro_workflow_runs", T, {
2251
- status: "suspended",
2252
- errorTag: "WorkflowCrashLooped",
2253
- errorMessage: e,
2254
- reclaimCount: n,
2255
- runnerEnteredAt: null
2256
- }));
2257
- t && v?.("workflowRuns", {
2258
- op: "update",
2259
- row: Z(t)
2260
- }), yield* m.promise(() => f.recordEvent({
2261
- runId: T,
2262
- eventType: "run-crashlooped",
2263
- payload: {
2264
- reclaimCount: n,
2265
- maxRunReclaims: r,
2266
- executionId: S,
2267
- tag: o.name
2268
- }
2269
- }));
2270
- })), h("workflow run parked after repeated runner deaths", {
2271
- tag: o.name,
2272
- executionId: S,
2273
- runId: T,
2274
- reclaimCount: n,
2275
- maxRunReclaims: r
2276
- });
2277
- let t = yield* le;
2278
- return yield* d.suspend(t);
2279
- }
2280
- k = yield* wn(o, T, h), yield* E("failed to record workflow re-entry", m.gen(function* () {
2281
- let t = yield* m.promise(() => o.store.update("_voltro_workflow_runs", T, {
2282
- status: "running",
2283
- errorTag: null,
2284
- errorMessage: null,
2285
- completedAt: null,
2286
- reclaimCount: n,
2287
- runnerEnteredAt: /* @__PURE__ */ new Date()
2288
- }));
2289
- t && v?.("workflowRuns", {
2290
- op: "update",
2291
- row: Z(t)
2292
- }), e && (yield* m.promise(() => f.recordEvent({
2293
- runId: T,
2294
- eventType: "run-resumed",
2295
- payload: {
2296
- reason: "runner-reclaim",
2297
- reclaimCount: n,
2298
- maxRunReclaims: r
2299
- }
2300
- })));
2301
- }));
2302
- } else yield* E("failed to record workflow start (continuing)", m.gen(function* () {
2303
- let e = yield* m.promise(() => o.store.insert("_voltro_workflow_runs", {
2304
- id: u("wr"),
2305
- tag: o.name,
2306
- executionId: S,
2307
- status: "running",
2308
- payload: te,
2309
- workflowVersion: o.workflowVersion ?? null,
2310
- workflowPatches: o.workflowPatches ?? null,
2311
- output: null,
2312
- subject: o.subject ?? null,
2313
- source: o.source ?? null,
2314
- errorTag: null,
2315
- errorMessage: null,
2316
- cancelled: !1,
2317
- startedAt: /* @__PURE__ */ new Date(),
2318
- completedAt: null,
2319
- durationMs: null,
2320
- traceId: o.traceId ?? null,
2321
- parentExecutionId: w,
2322
- parentClosePolicy: re,
2323
- runnerEnteredAt: /* @__PURE__ */ new Date(),
2324
- reclaimCount: 0
2325
- }));
2326
- if (T = e.id, v?.("workflowRuns", {
2327
- op: "insert",
2328
- row: Z(e)
2329
- }), T) {
2330
- let e = T;
2331
- yield* m.promise(() => f.recordEvent({
2332
- runId: e,
2333
- eventType: "run-started",
2334
- payload: {
2335
- tag: o.name,
2336
- executionId: S,
2337
- source: o.source ?? null,
2338
- workflowVersion: o.workflowVersion ?? null,
2339
- workflowPatches: o.workflowPatches ?? null,
2340
- parentExecutionId: w,
2341
- parentClosePolicy: re
2342
- }
2343
- }));
2344
- }
2345
- }));
2346
- let ae = o.subject?.tenantId, oe = c(te, S).pipe(m.locally(a, T), m.locally(r, S), m.locally(t, typeof ae == "string" ? ae : void 0), m.locally(i, ie), m.locally(s, k), m.provideService(n, f)), se = o.pluginWorkflowStepLayer ? oe.pipe(m.provide(o.pluginWorkflowStepLayer)) : oe, A = yield* d.intoResult(se);
2347
- if (d.isResult(A) && A._tag === "Suspended") {
2348
- let e = A.cause, t = e !== void 0 && !p.isEmpty(e), n = t ? p.squash(e) : void 0, r = n && typeof n == "object" && "_tag" in n ? String(n._tag) : null, i = t ? n?.message ?? String(n) : null;
2349
- t && (yield* m.sync(() => ee({
2350
- error: n,
2351
- source: "workflow",
2352
- name: o.name,
2353
- ...o.traceId ? { traceId: o.traceId } : {},
2354
- fields: {
2355
- executionId: S,
2356
- suspendedOnFailure: !0,
2357
- ...r ? { errorTag: r } : {},
2358
- ...T ? { runId: T } : {}
2359
- }
2360
- }))), T && (yield* E("failed to record workflow suspend", m.gen(function* () {
2361
- let e = yield* m.promise(() => o.store.update("_voltro_workflow_runs", T, {
2362
- status: "suspended",
2363
- runnerEnteredAt: null,
2364
- ...t ? {
2365
- errorTag: r,
2366
- errorMessage: i
2367
- } : {}
2368
- }));
2369
- e && v?.("workflowRuns", {
2370
- op: "update",
2371
- row: Z(e)
2372
- }), yield* m.promise(() => f.recordEvent({
2373
- runId: T,
2374
- eventType: "run-suspended",
2375
- payload: t ? {
2376
- reason: "suspend-on-failure",
2377
- errorTag: r,
2378
- errorMessage: i
2379
- } : { reason: "workflow-suspend" }
2380
- }));
2381
- })));
2382
- let a = yield* le;
2383
- return yield* d.suspend(a);
2384
- }
2385
- let j = A;
2386
- if (k !== void 0 && T !== void 0) {
2387
- let t = k.settle();
2388
- if (t.length > 0) {
2389
- let n = T;
2390
- h("workflow replay reached a different step shape than this run recorded", {
2391
- tag: o.name,
2392
- executionId: S,
2393
- runId: n,
2394
- findings: t.map((e) => `${e.kind}:${e.stepName}`)
2395
- }), yield* E("failed to record nondeterminism findings", m.promise(async () => {
2396
- for (let r of t) await f.recordEvent({
2397
- runId: n,
2398
- eventType: "nondeterminism-suspected",
2399
- payload: e(r)
2400
- }).catch(() => void 0);
2401
- }));
2402
- }
2403
- }
2404
- if (g.isFailure(j.exit)) {
2405
- let e = j.exit.cause, t = p.failureOption(e), n = t._tag === "Some" ? t.value : p.squash(e), r = n && typeof n == "object" && "_tag" in n ? String(n._tag) : null, i = n?.message ?? String(n);
2406
- return yield* m.sync(() => ee({
2407
- error: n,
2408
- source: "workflow",
2409
- name: o.name,
2410
- ...o.traceId ? { traceId: o.traceId } : {},
2411
- fields: {
2412
- executionId: S,
2413
- ...r ? { errorTag: r } : {},
2414
- ...T ? { runId: T } : {}
2415
- }
2416
- })), T && (yield* E("failed to record workflow failure", m.gen(function* () {
2417
- let e = yield* m.promise(() => o.store.update("_voltro_workflow_runs", T, {
2418
- status: "failed",
2419
- errorTag: r,
2420
- errorMessage: i,
2421
- completedAt: /* @__PURE__ */ new Date(),
2422
- durationMs: Date.now() - C,
2423
- runnerEnteredAt: null
2424
- }));
2425
- e && v?.("workflowRuns", {
2426
- op: "update",
2427
- row: Z(e)
2428
- }), yield* m.promise(() => f.recordEvent({
2429
- runId: T,
2430
- eventType: "run-failed",
2431
- payload: {
2432
- errorTag: r,
2433
- errorMessage: i,
2434
- durationMs: Date.now() - C
2435
- }
2436
- })), yield* y(S, "failed", T);
2437
- }))), yield* b(S, "failed", T, {
2438
- payload: te,
2439
- errorTag: r,
2440
- errorMessage: i
2441
- }), yield* m.sync(() => o.recordRun?.({
2442
- name: o.name,
2443
- status: "failed",
2444
- durationMs: Date.now() - C
2445
- })), yield* m.failCause(e);
2446
- }
2447
- let M = j.exit.value;
2448
- return T && (yield* E("failed to record workflow success", m.gen(function* () {
2449
- let e = yield* m.promise(() => o.store.update("_voltro_workflow_runs", T, {
2450
- status: "succeeded",
2451
- output: X(M, l),
2452
- completedAt: /* @__PURE__ */ new Date(),
2453
- durationMs: Date.now() - C,
2454
- runnerEnteredAt: null
2455
- }));
2456
- e && v?.("workflowRuns", {
2457
- op: "update",
2458
- row: Z(e)
2459
- }), yield* m.promise(() => f.recordEvent({
2460
- runId: T,
2461
- eventType: "run-succeeded",
2462
- payload: { durationMs: Date.now() - C }
2463
- })), yield* y(S, "succeeded", T);
2464
- }))), yield* b(S, "succeeded", T), yield* m.sync(() => o.recordRun?.({
2465
- name: o.name,
2466
- status: "succeeded",
2467
- durationMs: Date.now() - C,
2468
- completedAtSec: Date.now() / 1e3
2469
- })), M;
2470
- });
2471
- }, En = (e) => e === "cancel" || e === "terminate", Dn = (e) => e === "running" || e === "suspended", On = async (e) => {
2472
- let t = await e.store.query({
2473
- table: "_voltro_workflow_runs",
2474
- order: [{
2475
- column: "startedAt",
2476
- direction: "asc"
2477
- }],
2478
- predicate: x("parentExecutionId", e.parentExecutionId),
2479
- projection: void 0,
2480
- skip: void 0,
2481
- take: e.limit ?? 1e3
2482
- }), n = [];
2483
- for (let r of t) {
2484
- let t = {
2485
- runId: r.id,
2486
- workflowName: r.tag,
2487
- executionId: r.executionId,
2488
- policy: r.parentClosePolicy
2489
- };
2490
- if (r.parentClosePolicy === "abandon") {
2491
- n.push({
2492
- ...t,
2493
- action: "abandoned"
2494
- });
2495
- continue;
2496
- }
2497
- if (!En(r.parentClosePolicy)) {
2498
- n.push({
2499
- ...t,
2500
- action: "skipped",
2501
- reason: "no-parent-close-policy"
2502
- });
2503
- continue;
2504
- }
2505
- if (!Dn(r.status)) {
2506
- n.push({
2507
- ...t,
2508
- action: "skipped",
2509
- reason: `status:${r.status}`
2510
- });
2511
- continue;
2512
- }
2513
- try {
2514
- await e.interruptChild(r.tag, r.executionId, r.parentClosePolicy);
2515
- let i = await e.store.update("_voltro_workflow_runs", r.id, {
2516
- status: "cancelled",
2517
- cancelled: !0,
2518
- completedAt: /* @__PURE__ */ new Date()
2519
- });
2520
- i && e.emit?.("workflowRuns", {
2521
- op: "update",
2522
- row: Z(i)
2523
- }), await e.recorder?.recordEvent({
2524
- runId: r.id,
2525
- eventType: "run-cancelled",
2526
- payload: {
2527
- reason: "parent-close",
2528
- parentExecutionId: e.parentExecutionId,
2529
- parentStatus: e.parentStatus,
2530
- parentClosePolicy: r.parentClosePolicy,
2531
- action: r.parentClosePolicy
2532
- }
2533
- }), n.push({
2534
- ...t,
2535
- action: "cancelled"
2536
- });
2537
- } catch (i) {
2538
- let a = i?.message ?? String(i);
2539
- e.log?.warn("workflow.parentClose.childInterrupt failed", {
2540
- parentExecutionId: e.parentExecutionId,
2541
- childExecutionId: r.executionId,
2542
- childWorkflowName: r.tag,
2543
- parentClosePolicy: r.parentClosePolicy,
2544
- reason: a
2545
- }), n.push({
2546
- ...t,
2547
- action: "failed",
2548
- reason: a
2549
- });
2550
- }
2551
- }
2552
- return n;
2553
- }, kn = (e) => {
2554
- if (e == null) return null;
2555
- if (e instanceof Date) return e;
2556
- if (typeof e == "string" || typeof e == "number") {
2557
- let t = new Date(e);
2558
- return Number.isNaN(t.getTime()) ? null : t;
2559
- }
2560
- return null;
2561
- }, Q = (e) => typeof e == "number" ? e : e == null ? null : Number(e), $ = (e) => e == null ? null : String(e), An = (e) => {
2562
- let t = /* @__PURE__ */ new Map();
2563
- for (let n of e) {
2564
- let e = String(n.stepName), r = t.get(e);
2565
- r === void 0 ? t.set(e, [n]) : r.push(n);
2566
- }
2567
- let n = [];
2568
- for (let [e, r] of t) {
2569
- r.sort((e, t) => (Q(e.attempt) ?? 0) - (Q(t.attempt) ?? 0));
2570
- let t = r[r.length - 1], i = $(t.errorTag), a = $(t.errorMessage), o = i !== null || a !== null ? {
2571
- tag: i,
2572
- message: a ?? ""
2573
- } : null;
2574
- n.push({
2575
- name: e,
2576
- attempt: Q(t.attempt) ?? r.length,
2577
- attempts: r.length,
2578
- status: t.status ?? "running",
2579
- input: t.input ?? null,
2580
- output: t.output ?? null,
2581
- error: o,
2582
- durationMs: Q(t.durationMs)
2583
- });
2584
- }
2585
- return n.sort((t, n) => {
2586
- let r = e.find((e) => String(e.stepName) === t.name), i = e.find((e) => String(e.stepName) === n.name);
2587
- return (kn(r?.startedAt)?.getTime() ?? 0) - (kn(i?.startedAt)?.getTime() ?? 0);
2588
- }), n;
2589
- }, jn = (e) => {
2590
- if (e == null) return null;
2591
- if (typeof e == "string") try {
2592
- return JSON.parse(e);
2593
- } catch {
2594
- return null;
2595
- }
2596
- return typeof e == "object" ? e : null;
2597
- }, Mn = async (e, t) => {
2598
- let n = k(de), r = (await t.query(n.where(ie(x("id", e), x("executionId", e))).limit(1).descriptor))[0];
2599
- if (r === void 0) return null;
2600
- let i = String(r.id), a = k(fe), o = await t.query(a.where(x("runId", i)).descriptor);
2601
- return {
2602
- id: i,
2603
- executionId: $(r.executionId) ?? "",
2604
- name: $(r.tag) ?? "",
2605
- status: r.status ?? "running",
2606
- input: r.payload ?? null,
2607
- output: r.output ?? null,
2608
- subject: jn(r.subject),
2609
- source: $(r.source),
2610
- steps: An(o),
2611
- startedAt: kn(r.startedAt) ?? /* @__PURE__ */ new Date(0),
2612
- finishedAt: kn(r.completedAt),
2613
- traceId: $(r.traceId),
2614
- parentExecutionId: $(r.parentExecutionId),
2615
- parentClosePolicy: $(r.parentClosePolicy)
2616
- };
2617
- }, Nn = () => {
2618
- let e = [], t = [], r = 0, i = 0;
2619
- return {
2620
- layer: v.succeed(n, {
2621
- startStep: async ({ runId: t, stepName: n, attempt: i, stepInput: a, retryPolicy: o }) => {
2622
- let s = `wfstep_mem_${++r}`;
2623
- return e.push({
2624
- id: s,
2625
- runId: t,
2626
- stepName: n,
2627
- attempt: i,
2628
- status: "running",
2629
- input: a ?? null,
2630
- retryPolicy: o ?? null,
2631
- output: null,
2632
- errorTag: null,
2633
- errorMessage: null,
2634
- errorCause: null,
2635
- startedAt: /* @__PURE__ */ new Date(),
2636
- completedAt: null,
2637
- durationMs: null
2638
- }), s;
2639
- },
2640
- endStepSuccess: async ({ stepRecordId: t, output: n, durationMs: r }) => {
2641
- let i = e.find((e) => e.id === t);
2642
- i !== void 0 && (i.status = "succeeded", i.output = n, i.completedAt = /* @__PURE__ */ new Date(), i.durationMs = r);
2643
- },
2644
- endStepFailure: async ({ stepRecordId: t, errorTag: n, errorMessage: r, errorCause: i, durationMs: a }) => {
2645
- let o = e.find((e) => e.id === t);
2646
- o !== void 0 && (o.status = "failed", o.errorTag = n, o.errorMessage = r, o.errorCause = i ?? null, o.completedAt = /* @__PURE__ */ new Date(), o.durationMs = a);
2647
- },
2648
- recordEvent: async ({ runId: e, eventType: n, payload: r, stepName: a, attempt: o }) => {
2649
- let s = `wfev_mem_${++i}`;
2650
- return t.push({
2651
- id: s,
2652
- runId: e,
2653
- eventType: n,
2654
- payload: r ?? null,
2655
- stepName: a ?? null,
2656
- attempt: o ?? null,
2657
- occurredAt: /* @__PURE__ */ new Date()
2658
- }), { id: s };
2659
- }
2660
- }),
2661
- readSteps: () => e,
2662
- readEvents: () => t
2663
- };
2664
- };
2665
- //#endregion
2666
- export { $e as $, Ut as A, Ce as At, ut as B, de as Bt, on as C, Re as Ct, Bt as D, Te as Dt, Kt as E, ve as Et, jt as F, _e as Ft, rt as G, dt as H, kt as I, he as It, tt as J, it as K, Ot as L, me as Lt, Pt as M, ye as Mt, Et as N, P as Nt, Vt as O, xe as Ot, Mt as P, ge as Pt, et as Q, yt as R, pe as Rt, un as S, V as St, Xt as T, Ge as Tt, _t as U, ft as V, ue as Vt, W, lt as X, at as Y, ot as Z, en as _, Be as _t, vn as a, Ee as at, fn as b, Ne as bt, yn as c, We as ct, Tn as d, ze as dt, Ze as et, hn as f, Ke as ft, tn as g, Oe as gt, an as h, je as ht, _n as i, De as it, It as j, be as jt, Ht as k, we as kt, Z as l, H as lt, rn as m, Ie as mt, Mn as n, Xe as nt, Cn as o, I as ot, Y as p, U as pt, nt as q, On as r, L as rt, bn as s, Ve as st, Nn as t, Je as tt, X as u, He as ut, $t as v, Fe as vt, Yt as w, Me as wt, dn as x, Ae as xt, Qt as y, qe as yt, bt as z, fe as zt };