@voltro/workflow 0.85.0 → 0.87.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5987 -0
- package/THIRD-PARTY-NOTICES.md +1122 -31
- package/dist/admission.js +140 -0
- package/dist/admissionDrainer.js +705 -0
- package/dist/admissionGate.js +115 -0
- package/dist/admissionStore.js +347 -0
- package/dist/admissionSubmission.js +297 -0
- package/dist/admissionTables.js +137 -0
- package/dist/admissionTransaction.js +21 -0
- package/dist/awaitEvent.js +82 -0
- package/dist/budgetHold.js +136 -0
- package/dist/cancelOnPlan.js +75 -0
- package/dist/cancelOnSweep.js +188 -0
- package/dist/cancelPendingStart.js +50 -0
- package/dist/cluster.d.ts +111 -27
- package/dist/cluster.js +12 -2
- package/dist/clusterCron.js +19 -0
- package/dist/clusterDiagnostics.js +20 -0
- package/dist/clusterDiagnosticsSql.js +145 -0
- package/dist/clusterLayer.js +145 -0
- package/dist/clusterMigrationGate.js +61 -0
- package/dist/clusterRunnerLayer.js +31 -0
- package/dist/clusterShardGroups.js +33 -0
- package/dist/clusterTestSuite.d.ts +23 -0
- package/dist/clusterTestSuite.js +209 -179
- package/dist/controlMonitor.js +13 -0
- package/dist/controlRequest.js +367 -0
- package/dist/executionRefusal.js +162 -0
- package/dist/failureHandoff.js +183 -0
- package/dist/failureMessage.js +12 -0
- package/dist/failureRecovery.js +50 -0
- package/dist/failureReportStore.js +60 -0
- package/dist/flowControl.js +142 -0
- package/dist/forwardStartReceipts.js +41 -0
- package/dist/inMemoryLayer.js +7 -0
- package/dist/inMemoryRecorder.js +56 -0
- package/dist/index.d.ts +129 -30
- package/dist/index.js +50 -5
- package/dist/inspectWorkflow.js +101 -0
- package/dist/{journalEncryption-DTyhUzaS.js → journalEncryption.js} +30 -37
- package/dist/journalRoutingGuard.js +50 -0
- package/dist/journalRoutingLayout.js +47 -0
- package/dist/journalRoutingLock.js +39 -0
- package/dist/journalRoutingMaintenance.js +24 -0
- package/dist/journalRoutingMessageStorage.js +32 -0
- package/dist/journalRoutingNamespace.js +23 -0
- package/dist/journalRoutingRuntime.js +33 -0
- package/dist/journalRoutingSharding.js +28 -0
- package/dist/journalRoutingState.js +93 -0
- package/dist/journalRoutingTable.js +11 -0
- package/dist/journalRoutingTransaction.js +16 -0
- package/dist/messages.js +92 -0
- package/dist/nondeterminism.js +51 -0
- package/dist/parentClosure.js +141 -0
- package/dist/parentClosureRecovery.js +54 -0
- package/dist/pendingSubmission.js +85 -0
- package/dist/prepareSubmissionDispatch.js +17 -0
- package/dist/preparedExecution.js +14 -0
- package/dist/primitives.js +225 -2
- package/dist/queuedCancellationRequest.js +364 -0
- package/dist/queuedControl.js +21 -0
- package/dist/recorder.js +11 -0
- package/dist/residentExecutionEvidence.js +64 -0
- package/dist/retryPolicy.js +57 -0
- package/dist/runEventsTable.js +17 -0
- package/dist/runGeneration.js +345 -0
- package/dist/runRecording.js +615 -0
- package/dist/runStepsTable.js +28 -0
- package/dist/runnerStorageGuard.js +29 -0
- package/dist/runsTable.js +42 -0
- package/dist/scheduleDeclaration.js +44 -0
- package/dist/signalHint.js +23 -0
- package/dist/signals.js +70 -0
- package/dist/signalsSuspending.js +57 -0
- package/dist/sqliteWorkflowOwnership.js +26 -0
- package/dist/stalenessSweep.js +191 -0
- package/dist/startContextsTable.js +20 -0
- package/dist/startReceipt.js +143 -0
- package/dist/submissionRecovery.js +122 -0
- package/dist/submissionRejection.js +10 -0
- package/dist/submissionRetry.js +71 -0
- package/dist/suspensionUnavailable.js +9 -0
- package/dist/updates.js +87 -0
- package/dist/watermarkTable.js +9 -0
- package/dist/webCrypto.js +17 -0
- package/dist/workflowDelivery.js +24 -0
- package/dist/workflowExecutorRouting.js +33 -0
- package/dist/workflowJournal.js +124 -0
- package/dist/workflowJournalReset.js +111 -0
- package/dist/workflowReadSelections.js +12 -0
- package/dist/workflowRestartDispatch.js +35 -0
- package/dist/workflowRestartObservation.js +60 -0
- package/dist/workflowRestartPreparation.js +109 -0
- package/dist/workflowRestartReservation.js +427 -0
- package/dist/workflowResumeDispatch.js +30 -0
- package/dist/workflowRuntimeReadiness.js +12 -0
- package/dist/workflowShardRelocation.js +58 -0
- package/dist/workflowShardRelocationSql.js +72 -0
- package/package.json +4 -4
- package/dist/cluster-F_bhqVP7.js +0 -679
- package/dist/primitives-DX04WTWh.js +0 -507
- package/dist/src-C2NEyUM8.js +0 -3925
- package/dist/workflowReadSelections-CZAUjP7f.js +0 -2096
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
import { dispatchedExecutionSubmissions as e, readAdmissionSubmission as t } from "./admissionSubmission.js";
|
|
2
|
+
import { readProvenSubmissionRejection as n } from "./submissionRejection.js";
|
|
3
|
+
import { decodeWorkflowStartReceipt as r, readWorkflowStartReceipt as i } from "./startReceipt.js";
|
|
4
|
+
import { cancelPendingWorkflowStartInTransaction as a } from "./cancelPendingStart.js";
|
|
5
|
+
import { acceptWorkflowControlInTransaction as o, readWorkflowControlInTransaction as s } from "./controlRequest.js";
|
|
6
|
+
import { cancelSuspendedWorkflowRunInTransaction as c } from "./runGeneration.js";
|
|
7
|
+
import { Schema as l } from "effect";
|
|
8
|
+
import { WorkflowQueuedCancellationResultSchema as u } from "@voltro/protocol";
|
|
9
|
+
import { and as d, derivedRowId as f, eq as p, gt as m, id as h, json as g, table as _, text as v, timestamp as y } from "@voltro/database";
|
|
10
|
+
//#region src/queuedCancellationRequest.ts
|
|
11
|
+
var b = _("_voltro_workflow_queued_cancellations", {
|
|
12
|
+
id: h({ prefix: "wfqc" }),
|
|
13
|
+
receiptId: v(),
|
|
14
|
+
workflowName: v(),
|
|
15
|
+
tenantId: v().nullable(),
|
|
16
|
+
requestedAt: y(),
|
|
17
|
+
cause: g().nullable(),
|
|
18
|
+
target: g(),
|
|
19
|
+
controlBinding: g().nullable()
|
|
20
|
+
}).index(["receiptId"]).index(["workflowName", "id"]).nonReactive(), x = l.NullOr(l.Struct({
|
|
21
|
+
reason: l.NonEmptyString,
|
|
22
|
+
detail: l.optional(l.Record(l.String, l.Unknown))
|
|
23
|
+
})), S = l.Struct({
|
|
24
|
+
id: l.NonEmptyString,
|
|
25
|
+
receiptId: l.NonEmptyString,
|
|
26
|
+
workflowName: l.NonEmptyString,
|
|
27
|
+
tenantId: l.NullOr(l.String),
|
|
28
|
+
requestedAt: l.Date,
|
|
29
|
+
cause: x,
|
|
30
|
+
controlBinding: l.NullOr(l.Struct({
|
|
31
|
+
controlId: l.NonEmptyString,
|
|
32
|
+
runId: l.NonEmptyString,
|
|
33
|
+
executionId: l.NonEmptyString,
|
|
34
|
+
generation: l.NonEmptyString
|
|
35
|
+
})),
|
|
36
|
+
target: l.Union([l.Struct({
|
|
37
|
+
kind: l.Literal("submission"),
|
|
38
|
+
submissionId: l.NonEmptyString
|
|
39
|
+
}), l.Struct({
|
|
40
|
+
kind: l.Literal("terminal"),
|
|
41
|
+
receipt: l.Unknown
|
|
42
|
+
})])
|
|
43
|
+
}), C = (e) => {
|
|
44
|
+
let t = l.decodeUnknownSync(S)(e);
|
|
45
|
+
if (!Number.isFinite(t.requestedAt.getTime())) throw Error("Queued cancellation request has an invalid timestamp");
|
|
46
|
+
if (t.target.kind === "submission") return {
|
|
47
|
+
...t,
|
|
48
|
+
target: t.target
|
|
49
|
+
};
|
|
50
|
+
let n = r(t.target.receipt);
|
|
51
|
+
if (t.controlBinding !== null) throw Error("A non-executed start cannot have a run control binding");
|
|
52
|
+
if (n.id !== t.receiptId || n.workflowName !== t.workflowName || n.tenantId !== t.tenantId || n.terminal === null) throw Error("Queued cancellation terminal evidence belongs to another start or is not terminal");
|
|
53
|
+
return {
|
|
54
|
+
...t,
|
|
55
|
+
target: {
|
|
56
|
+
kind: "terminal",
|
|
57
|
+
receipt: n
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
}, w = async (e, t) => {
|
|
61
|
+
let [n] = await e.query({
|
|
62
|
+
table: b.tableName,
|
|
63
|
+
predicate: p("id", t),
|
|
64
|
+
lock: "update",
|
|
65
|
+
order: [],
|
|
66
|
+
take: 1,
|
|
67
|
+
skip: void 0,
|
|
68
|
+
projection: void 0
|
|
69
|
+
});
|
|
70
|
+
return n === void 0 ? void 0 : C(n);
|
|
71
|
+
}, T = async (e, t) => {
|
|
72
|
+
let n = t.controlBinding;
|
|
73
|
+
if (n === null) throw Error("Queued cancellation has no control binding");
|
|
74
|
+
let r = await s(e, n.controlId);
|
|
75
|
+
if (r === void 0 || r.operation !== "cancel" || r.workflowName !== t.workflowName || r.runId !== n.runId || r.executionId !== n.executionId || r.generation !== n.generation || r.owner?.tenantId !== t.tenantId || r.result?.status === "running") throw Error("Queued cancellation lost its original resident control owner");
|
|
76
|
+
return r;
|
|
77
|
+
}, E = async (e, t, n) => {
|
|
78
|
+
if (t.controlBinding === null) return;
|
|
79
|
+
let r = await T(e, t);
|
|
80
|
+
if (r.result !== null) return;
|
|
81
|
+
let [i] = await e.query({
|
|
82
|
+
table: "_voltro_workflow_runs",
|
|
83
|
+
predicate: p("id", r.runId),
|
|
84
|
+
lock: "update",
|
|
85
|
+
order: [],
|
|
86
|
+
take: 1,
|
|
87
|
+
skip: void 0,
|
|
88
|
+
projection: void 0
|
|
89
|
+
});
|
|
90
|
+
i !== void 0 && await c(e, {
|
|
91
|
+
runId: r.runId,
|
|
92
|
+
workflowName: r.workflowName,
|
|
93
|
+
executionId: r.executionId,
|
|
94
|
+
generation: r.generation
|
|
95
|
+
}, n);
|
|
96
|
+
}, D = async (e, r) => {
|
|
97
|
+
let i = await w(e, r.requestId);
|
|
98
|
+
if (i === void 0) return {
|
|
99
|
+
kind: "unknown",
|
|
100
|
+
reason: "missing-request"
|
|
101
|
+
};
|
|
102
|
+
if (i.workflowName !== r.workflowName || i.tenantId !== r.tenantId) throw Error("Queued cancellation request belongs to another workflow or tenant");
|
|
103
|
+
if (i.target.kind === "terminal") {
|
|
104
|
+
let e = i.target.receipt.terminal;
|
|
105
|
+
if (e === null) throw Error("Queued cancellation has no terminal evidence");
|
|
106
|
+
return {
|
|
107
|
+
kind: e.kind === "cancelled" ? "confirmed" : "already-terminal",
|
|
108
|
+
request: i,
|
|
109
|
+
outcome: e
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
if (i.controlBinding !== null) {
|
|
113
|
+
let t = await T(e, i);
|
|
114
|
+
if (t.result !== null) return {
|
|
115
|
+
kind: t.result.kind,
|
|
116
|
+
request: i,
|
|
117
|
+
control: t
|
|
118
|
+
};
|
|
119
|
+
let [n] = await e.query({
|
|
120
|
+
table: "_voltro_workflow_runs",
|
|
121
|
+
predicate: p("id", t.runId),
|
|
122
|
+
lock: "update",
|
|
123
|
+
order: [],
|
|
124
|
+
take: 1,
|
|
125
|
+
skip: void 0,
|
|
126
|
+
projection: void 0
|
|
127
|
+
});
|
|
128
|
+
if (n === void 0) return {
|
|
129
|
+
kind: "unknown",
|
|
130
|
+
reason: "missing-run",
|
|
131
|
+
request: i,
|
|
132
|
+
control: t
|
|
133
|
+
};
|
|
134
|
+
if (n.tag !== t.workflowName || n.executionId !== t.executionId) throw Error("Queued cancellation control belongs to another resident execution");
|
|
135
|
+
return n.runnerGeneration !== t.generation || n.status !== "running" && n.status !== "suspended" ? {
|
|
136
|
+
kind: "unknown",
|
|
137
|
+
reason: "unconfirmed-generation",
|
|
138
|
+
request: i,
|
|
139
|
+
control: t
|
|
140
|
+
} : {
|
|
141
|
+
kind: "accepted",
|
|
142
|
+
request: i,
|
|
143
|
+
control: t,
|
|
144
|
+
run: n
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
let a = await t(e, i.target.submissionId);
|
|
148
|
+
if (a === void 0 || !a.receiptsBound || a.workflowName !== i.workflowName || a.tenantId !== i.tenantId) throw Error("Queued cancellation has no matching submission evidence");
|
|
149
|
+
return a.failureId === null ? a.retry.stoppedAt !== null || a.runId !== null ? {
|
|
150
|
+
kind: "unknown",
|
|
151
|
+
reason: "unbound-submission",
|
|
152
|
+
request: i
|
|
153
|
+
} : {
|
|
154
|
+
kind: "accepted",
|
|
155
|
+
request: i
|
|
156
|
+
} : {
|
|
157
|
+
kind: "already-terminal",
|
|
158
|
+
request: i,
|
|
159
|
+
outcome: {
|
|
160
|
+
kind: "rejected",
|
|
161
|
+
failureId: await n(e, a)
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
}, O = (e, t) => {
|
|
165
|
+
let n = "request" in t ? t.request : void 0;
|
|
166
|
+
if (n !== void 0 && (n.id !== e.requestId || n.receiptId !== e.receiptId || n.workflowName !== e.workflowName)) throw Error("Queued control result belongs to another request or receipt");
|
|
167
|
+
let r = {
|
|
168
|
+
operation: "cancel",
|
|
169
|
+
workflowName: e.workflowName,
|
|
170
|
+
receiptId: e.receiptId,
|
|
171
|
+
requestId: n?.id ?? null,
|
|
172
|
+
kind: t.kind
|
|
173
|
+
}, i = l.decodeUnknownSync(u);
|
|
174
|
+
if (t.kind === "unknown") return i({
|
|
175
|
+
...r,
|
|
176
|
+
observation: {
|
|
177
|
+
kind: "unavailable",
|
|
178
|
+
reason: t.reason
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
if ("outcome" in t && t.outcome !== void 0) return i({
|
|
182
|
+
...r,
|
|
183
|
+
observation: {
|
|
184
|
+
kind: "admission",
|
|
185
|
+
outcome: t.outcome
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
if ("control" in t && t.control !== void 0) {
|
|
189
|
+
let e = t.control, n = e.result;
|
|
190
|
+
return i({
|
|
191
|
+
...r,
|
|
192
|
+
observation: {
|
|
193
|
+
kind: "execution",
|
|
194
|
+
snapshot: {
|
|
195
|
+
id: e.runId,
|
|
196
|
+
workflowName: e.workflowName,
|
|
197
|
+
executionId: e.executionId,
|
|
198
|
+
status: n?.status ?? ("run" in t ? t.run?.status : void 0),
|
|
199
|
+
...n !== null && n.status === "succeeded" ? { output: n.output } : {},
|
|
200
|
+
...n !== null && n.status === "failed" && n.errorMessage !== null ? { error: {
|
|
201
|
+
tag: n.errorTag,
|
|
202
|
+
message: n.errorMessage
|
|
203
|
+
} } : {}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
return i({
|
|
209
|
+
...r,
|
|
210
|
+
observation: { kind: "pending" }
|
|
211
|
+
});
|
|
212
|
+
}, k = async (e, n) => {
|
|
213
|
+
let r = l.decodeUnknownSync(l.Struct({
|
|
214
|
+
id: l.NonEmptyString,
|
|
215
|
+
receiptId: l.NonEmptyString,
|
|
216
|
+
workflowName: l.NonEmptyString,
|
|
217
|
+
tenantId: l.NullOr(l.String),
|
|
218
|
+
requestedAt: l.Date,
|
|
219
|
+
cause: x
|
|
220
|
+
}))({
|
|
221
|
+
id: n.requestId,
|
|
222
|
+
receiptId: n.receiptId,
|
|
223
|
+
workflowName: n.workflowName,
|
|
224
|
+
tenantId: n.tenantId,
|
|
225
|
+
requestedAt: new Date(n.now),
|
|
226
|
+
cause: n.cause ?? null
|
|
227
|
+
});
|
|
228
|
+
if (!Number.isFinite(r.requestedAt.getTime())) throw Error("Queued cancellation request requires a valid timestamp");
|
|
229
|
+
let o = await w(e, r.id);
|
|
230
|
+
if (o !== void 0) {
|
|
231
|
+
if (o.receiptId !== r.receiptId || o.workflowName !== r.workflowName || o.tenantId !== r.tenantId) throw Error("Queued cancellation identity belongs to a different start or owner");
|
|
232
|
+
return await E(e, o, n.now), o;
|
|
233
|
+
}
|
|
234
|
+
let s = await a(e, n), c;
|
|
235
|
+
if (s.kind === "submitted") c = {
|
|
236
|
+
kind: "submission",
|
|
237
|
+
submissionId: s.submissionId
|
|
238
|
+
};
|
|
239
|
+
else {
|
|
240
|
+
let t = await i(e, n.receiptId);
|
|
241
|
+
if (t === void 0) throw Error("Cancelled start receipt disappeared during request acceptance");
|
|
242
|
+
c = {
|
|
243
|
+
kind: "terminal",
|
|
244
|
+
receipt: t
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
let u = C({
|
|
248
|
+
...r,
|
|
249
|
+
target: c,
|
|
250
|
+
controlBinding: null
|
|
251
|
+
});
|
|
252
|
+
if (await e.insert(b.tableName, u), c.kind === "submission") {
|
|
253
|
+
let r = await t(e, c.submissionId);
|
|
254
|
+
if (r === void 0) throw Error("Queued cancellation submission disappeared during acceptance");
|
|
255
|
+
if (r.preparedExecutionId !== null && r.dispatchAttempts > 0) {
|
|
256
|
+
let [t] = await e.query({
|
|
257
|
+
table: "_voltro_workflow_runs",
|
|
258
|
+
predicate: p("executionId", r.preparedExecutionId),
|
|
259
|
+
lock: "update",
|
|
260
|
+
order: [],
|
|
261
|
+
take: 1,
|
|
262
|
+
skip: void 0,
|
|
263
|
+
projection: void 0
|
|
264
|
+
});
|
|
265
|
+
if (t !== void 0) {
|
|
266
|
+
let r = l.decodeUnknownSync(l.Struct({
|
|
267
|
+
id: l.NonEmptyString,
|
|
268
|
+
tag: l.NonEmptyString,
|
|
269
|
+
executionId: l.NonEmptyString,
|
|
270
|
+
runnerGeneration: l.NonEmptyString
|
|
271
|
+
}))(t), i = {
|
|
272
|
+
runId: r.id,
|
|
273
|
+
workflowName: r.tag,
|
|
274
|
+
executionId: r.executionId,
|
|
275
|
+
generation: r.runnerGeneration
|
|
276
|
+
}, a = await A(e, u.id, i);
|
|
277
|
+
return await E(e, a.request, n.now), a.request;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return u;
|
|
282
|
+
}, A = async (e, n, r) => {
|
|
283
|
+
let i = await w(e, n);
|
|
284
|
+
if (i === void 0) throw Error("Queued cancellation request is missing");
|
|
285
|
+
if (i.target.kind === "terminal") return {
|
|
286
|
+
kind: "terminal",
|
|
287
|
+
request: i
|
|
288
|
+
};
|
|
289
|
+
if (i.controlBinding !== null) return {
|
|
290
|
+
kind: "bound",
|
|
291
|
+
request: i,
|
|
292
|
+
control: await T(e, i)
|
|
293
|
+
};
|
|
294
|
+
let a = await t(e, i.target.submissionId);
|
|
295
|
+
if (a === void 0 || a.workflowName !== i.workflowName || a.tenantId !== i.tenantId || !a.receiptsBound || a.failureId !== null || a.dispatchAttempts === 0 || a.preparedExecutionId !== r.executionId || a.executionId !== null && a.executionId !== r.executionId || a.runId !== null && a.runId !== r.runId || r.workflowName !== i.workflowName) throw Error("Queued cancellation has no dispatched submission for this resident execution");
|
|
296
|
+
let [s] = await e.query({
|
|
297
|
+
table: "_voltro_workflow_runs",
|
|
298
|
+
predicate: p("id", r.runId),
|
|
299
|
+
lock: "update",
|
|
300
|
+
order: [],
|
|
301
|
+
take: 1,
|
|
302
|
+
skip: void 0,
|
|
303
|
+
projection: void 0
|
|
304
|
+
}), c = l.decodeUnknownOption(l.Struct({ tenantId: l.NullOr(l.String) }))(s?.subject);
|
|
305
|
+
if (s === void 0 || s.tag !== r.workflowName || s.executionId !== r.executionId || s.runnerGeneration !== r.generation || c._tag === "None" || c.value.tenantId !== i.tenantId || ![
|
|
306
|
+
"running",
|
|
307
|
+
"suspended",
|
|
308
|
+
"succeeded",
|
|
309
|
+
"failed",
|
|
310
|
+
"cancelled"
|
|
311
|
+
].includes(String(s.status))) throw Error("Queued cancellation generation or tenant does not match the resident run");
|
|
312
|
+
let u = {
|
|
313
|
+
controlId: f("wfctl", JSON.stringify(["queued-cancel", i.id])),
|
|
314
|
+
runId: r.runId,
|
|
315
|
+
executionId: r.executionId,
|
|
316
|
+
generation: r.generation
|
|
317
|
+
}, d = await o(e, {
|
|
318
|
+
id: u.controlId,
|
|
319
|
+
...r,
|
|
320
|
+
operation: "cancel",
|
|
321
|
+
requestedAt: i.requestedAt.getTime(),
|
|
322
|
+
cause: i.cause
|
|
323
|
+
});
|
|
324
|
+
if (await e.update(b.tableName, i.id, { controlBinding: u }) === null) throw Error("Queued cancellation request disappeared during run binding");
|
|
325
|
+
return {
|
|
326
|
+
kind: "bound",
|
|
327
|
+
request: {
|
|
328
|
+
...i,
|
|
329
|
+
controlBinding: u
|
|
330
|
+
},
|
|
331
|
+
control: d
|
|
332
|
+
};
|
|
333
|
+
}, j = async (t, n) => {
|
|
334
|
+
let r = /* @__PURE__ */ new Set();
|
|
335
|
+
for await (let i of e(t, n.executionId, n.workflowName)) r.add(i.id);
|
|
336
|
+
if (r.size === 0) return !1;
|
|
337
|
+
let i, a = !1;
|
|
338
|
+
for (;;) {
|
|
339
|
+
let e = await t.query({
|
|
340
|
+
table: b.tableName,
|
|
341
|
+
predicate: d(p("workflowName", n.workflowName), ...i === void 0 ? [] : [m("id", i)]),
|
|
342
|
+
lock: "update",
|
|
343
|
+
order: [{
|
|
344
|
+
column: "id",
|
|
345
|
+
direction: "asc"
|
|
346
|
+
}],
|
|
347
|
+
take: 100,
|
|
348
|
+
skip: void 0,
|
|
349
|
+
projection: void 0
|
|
350
|
+
});
|
|
351
|
+
for (let o of e) {
|
|
352
|
+
let e = C(o);
|
|
353
|
+
if (i = e.id, e.target.kind !== "submission" || !r.has(e.target.submissionId)) continue;
|
|
354
|
+
let s = await A(t, e.id, n);
|
|
355
|
+
if (s.kind === "bound") {
|
|
356
|
+
if (s.control.runId !== n.runId || s.control.executionId !== n.executionId || s.control.workflowName !== n.workflowName) throw Error("Queued cancellation entry does not match its original resident execution");
|
|
357
|
+
s.control.result === null && (a = !0);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
if (e.length < 100) return a;
|
|
361
|
+
}
|
|
362
|
+
};
|
|
363
|
+
//#endregion
|
|
364
|
+
export { k as acceptQueuedCancellationInTransaction, A as bindQueuedCancellationRunInTransaction, D as observeQueuedCancellationInTransaction, b as queuedCancellationRequestsTable, O as queuedCancellationResult, w as readQueuedCancellationRequestInTransaction, j as stageQueuedCancellationsAtRunEntry };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { acceptQueuedCancellationInTransaction as e, observeQueuedCancellationInTransaction as t, queuedCancellationResult as n } from "./queuedCancellationRequest.js";
|
|
2
|
+
import { Schema as r } from "effect";
|
|
3
|
+
//#region src/queuedControl.ts
|
|
4
|
+
var i = r.Struct({
|
|
5
|
+
requestId: r.NonEmptyString,
|
|
6
|
+
receiptId: r.NonEmptyString,
|
|
7
|
+
workflowName: r.NonEmptyString,
|
|
8
|
+
tenantId: r.NullOr(r.String)
|
|
9
|
+
}), a = async (t, n) => {
|
|
10
|
+
let a = r.decodeUnknownSync(i)(n);
|
|
11
|
+
return await e(t, {
|
|
12
|
+
...a,
|
|
13
|
+
now: n.now,
|
|
14
|
+
...n.cause === void 0 ? {} : { cause: n.cause }
|
|
15
|
+
}), o(t, a);
|
|
16
|
+
}, o = async (e, a) => {
|
|
17
|
+
let o = r.decodeUnknownSync(i)(a);
|
|
18
|
+
return n(o, await t(e, o));
|
|
19
|
+
};
|
|
20
|
+
//#endregion
|
|
21
|
+
export { a as cancelQueuedWorkflowStartInTransaction, o as readQueuedWorkflowCancellationInTransaction };
|
package/dist/recorder.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Context as e, Effect as t } from "effect";
|
|
2
|
+
//#region src/recorder.ts
|
|
3
|
+
var n = class extends e.Service()("@voltro/WorkflowRunRecorder") {}, r = e.Reference("@voltro/workflow/CurrentWorkflowRunId", { defaultValue: () => void 0 }), i = e.Reference("@voltro/workflow/CurrentWorkflowExecutionId", { defaultValue: () => void 0 }), a = e.Reference("@voltro/workflow/CurrentWorkflowStep", { defaultValue: () => void 0 }), o = t.gen(function* () {
|
|
4
|
+
let e = yield* i, t = yield* a;
|
|
5
|
+
return e === void 0 || t === void 0 ? void 0 : {
|
|
6
|
+
executionId: e,
|
|
7
|
+
step: t
|
|
8
|
+
};
|
|
9
|
+
}), s = e.Reference("@voltro/workflow/CurrentWorkflowGeneration", { defaultValue: () => void 0 }), c = e.Reference("@voltro/workflow/CurrentWorkflowWakeTenant", { defaultValue: () => void 0 }), l = e.Reference("@voltro/workflow/CurrentWorkflowPatches", { defaultValue: () => [] }), u = () => r, d = () => i, f = class extends e.Service()("@voltro/WorkflowStepInterceptor") {};
|
|
10
|
+
//#endregion
|
|
11
|
+
export { i as CurrentWorkflowExecutionId, s as CurrentWorkflowGeneration, l as CurrentWorkflowPatches, r as CurrentWorkflowRunId, a as CurrentWorkflowStep, c as CurrentWorkflowWakeTenant, n as WorkflowRunRecorder, f as WorkflowStepInterceptorTag, o as currentWorkflowStep, d as getCurrentWorkflowExecutionId, u as getCurrentWorkflowRunId };
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Schema as e } from "effect";
|
|
2
|
+
import { eq as t } from "@voltro/database";
|
|
3
|
+
//#region src/residentExecutionEvidence.ts
|
|
4
|
+
var n = e.Struct({
|
|
5
|
+
runId: e.NonEmptyString,
|
|
6
|
+
workflowName: e.NonEmptyString,
|
|
7
|
+
executionId: e.NonEmptyString,
|
|
8
|
+
generation: e.NonEmptyString,
|
|
9
|
+
parentStatus: e.Literals([
|
|
10
|
+
"succeeded",
|
|
11
|
+
"failed",
|
|
12
|
+
"cancelled"
|
|
13
|
+
]),
|
|
14
|
+
closedAt: e.Date
|
|
15
|
+
}), r = async (r, i, a) => {
|
|
16
|
+
let [o] = await r.query({
|
|
17
|
+
table: "_voltro_workflow_runs",
|
|
18
|
+
predicate: t("executionId", a),
|
|
19
|
+
lock: "update",
|
|
20
|
+
order: [],
|
|
21
|
+
take: 1,
|
|
22
|
+
skip: void 0,
|
|
23
|
+
projection: void 0
|
|
24
|
+
});
|
|
25
|
+
if (o !== void 0) {
|
|
26
|
+
if (o.tag !== i) throw Error("Admission acknowledgement belongs to a different resident workflow");
|
|
27
|
+
if (typeof o.id != "string" || o.id.length === 0) throw Error("Resident execution has no run identity");
|
|
28
|
+
if (o.status === "running" || o.status === "suspended") return {
|
|
29
|
+
runId: o.id,
|
|
30
|
+
completedAt: null
|
|
31
|
+
};
|
|
32
|
+
if (o.status !== "succeeded" && o.status !== "failed" && o.status !== "cancelled") throw Error("Resident execution has an unrecognized status");
|
|
33
|
+
if (!(o.completedAt instanceof Date) || !Number.isFinite(o.completedAt.getTime())) throw Error("Terminal workflow has no valid completion timestamp for lease release");
|
|
34
|
+
return {
|
|
35
|
+
runId: o.id,
|
|
36
|
+
completedAt: o.completedAt
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
let [s] = await r.query({
|
|
40
|
+
table: "_voltro_workflow_parent_closures",
|
|
41
|
+
predicate: t("executionId", a),
|
|
42
|
+
lock: "update",
|
|
43
|
+
order: [{
|
|
44
|
+
column: "closedAt",
|
|
45
|
+
direction: "desc"
|
|
46
|
+
}, {
|
|
47
|
+
column: "id",
|
|
48
|
+
direction: "desc"
|
|
49
|
+
}],
|
|
50
|
+
take: 1,
|
|
51
|
+
skip: void 0,
|
|
52
|
+
projection: void 0
|
|
53
|
+
});
|
|
54
|
+
if (s === void 0) return;
|
|
55
|
+
let c = e.decodeUnknownSync(n)(s);
|
|
56
|
+
if (c.workflowName !== i || c.executionId !== a) throw Error("Admission acknowledgement belongs to a different resident workflow");
|
|
57
|
+
if (!Number.isFinite(c.closedAt.getTime())) throw Error("Workflow closure has no valid completion timestamp");
|
|
58
|
+
return {
|
|
59
|
+
runId: c.runId,
|
|
60
|
+
completedAt: c.closedAt
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
//#endregion
|
|
64
|
+
export { r as readResidentExecutionEvidence };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Cause as e, Duration as t, Effect as n, Exit as r, Option as i, Schedule as a } from "effect";
|
|
2
|
+
//#region src/retryPolicy.ts
|
|
3
|
+
var o = (e) => {
|
|
4
|
+
if (typeof e != "object" || !e) return;
|
|
5
|
+
let n = e.retryAfterMillis;
|
|
6
|
+
if (typeof n == "number" && Number.isFinite(n) && n >= 0) return t.millis(n);
|
|
7
|
+
let r = e.retryAfter;
|
|
8
|
+
if (typeof r == "number" && Number.isFinite(r) && r >= 0) return t.seconds(r);
|
|
9
|
+
}, s = (e) => t.fromInputUnsafe(e), c = (e) => typeof e == "object" && e && "_tag" in e ? String(e._tag) : void 0, l = (e) => e !== void 0 && (e.maxAttempts ?? 3) > 1, u = (e) => {
|
|
10
|
+
if (e.retryable) return e.retryable;
|
|
11
|
+
if (e.retryableErrors && e.retryableErrors.length > 0) {
|
|
12
|
+
let t = new Set(e.retryableErrors);
|
|
13
|
+
return (e) => {
|
|
14
|
+
let n = c(e);
|
|
15
|
+
return n !== void 0 && t.has(n);
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
return () => !0;
|
|
19
|
+
}, d = (e) => {
|
|
20
|
+
let r = e.baseDelay ?? "200 millis", i = e.strategy ?? "exponential", o = e.maxAttempts ?? 3, c = i === "linear" ? a.modifyDelay(a.spaced(s(e.step ?? r)), (i) => n.succeed(t.times(s(e.step ?? r), i.attempt))) : i === "fixed" ? a.spaced(s(r)) : a.exponential(s(r), e.factor ?? 2);
|
|
21
|
+
if (e.maxDelay !== void 0) {
|
|
22
|
+
let r = s(e.maxDelay);
|
|
23
|
+
c = a.modifyDelay(c, (e) => n.succeed(t.min(e.duration, r)));
|
|
24
|
+
}
|
|
25
|
+
(e.jitter ?? !0) === !0 && (c = a.jittered(c));
|
|
26
|
+
let l = a.max([c, a.recurs(Math.max(0, o - 1))]);
|
|
27
|
+
return e.maxElapsed !== void 0 && (l = a.upTo({ duration: s(e.maxElapsed) })(l)), l;
|
|
28
|
+
}, f = (e, n) => {
|
|
29
|
+
let r = t.toMillis(s(e.baseDelay ?? "200 millis")), i = e.strategy ?? "exponential", a = i === "fixed" ? r : i === "linear" ? r + t.toMillis(s(e.step ?? e.baseDelay ?? "200 millis")) * (n - 1) : r * (e.factor ?? 2) ** (n - 1);
|
|
30
|
+
return e.maxDelay !== void 0 && (a = Math.min(a, t.toMillis(s(e.maxDelay)))), (e.jitter ?? !0) === !0 && (a *= Math.random()), a;
|
|
31
|
+
}, p = (a, c, l, u) => n.gen(function* () {
|
|
32
|
+
let d = c.maxAttempts ?? 3, p = c.maxElapsed === void 0 ? Infinity : t.toMillis(s(c.maxElapsed)), m = yield* n.sync(() => Date.now()), h = 0;
|
|
33
|
+
for (;;) {
|
|
34
|
+
let s = yield* n.exit(a);
|
|
35
|
+
if (r.isSuccess(s)) return s.value;
|
|
36
|
+
let g = s.cause, _ = e.findErrorOption(g), v = i.isSome(_) ? _.value : e.squash(g);
|
|
37
|
+
h += 1;
|
|
38
|
+
let y = (yield* n.sync(() => Date.now())) - m;
|
|
39
|
+
if (h >= d || !l(v) || y >= p) return yield* n.failCause(g);
|
|
40
|
+
u?.(v);
|
|
41
|
+
let b = o(v), x = b === void 0 ? f(c, h) : t.toMillis(b);
|
|
42
|
+
yield* n.sleep(t.millis(x));
|
|
43
|
+
}
|
|
44
|
+
}), m = (e, t, r) => {
|
|
45
|
+
if (!l(t)) return e;
|
|
46
|
+
let i = u(t);
|
|
47
|
+
if (t.respectRetryAfter === !0) return p(e, t, i, r);
|
|
48
|
+
let a = d(t), o = r ? n.tapError(e, (e) => n.sync(() => {
|
|
49
|
+
i(e) && r(e);
|
|
50
|
+
})) : e;
|
|
51
|
+
return n.retry(o, {
|
|
52
|
+
schedule: a,
|
|
53
|
+
while: i
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
//#endregion
|
|
57
|
+
export { m as applyRetryPolicy, l as retryPolicyIsActive };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { _voltroWorkflowRunsTable as e } from "./runsTable.js";
|
|
2
|
+
import { id as t, integer as n, json as r, reference as i, table as a, text as o, timestamp as s } from "@voltro/database";
|
|
3
|
+
//#region src/runEventsTable.ts
|
|
4
|
+
var c = a("_voltro_workflow_run_events", {
|
|
5
|
+
id: t({ prefix: "wfev" }),
|
|
6
|
+
runId: i(() => e, {
|
|
7
|
+
index: !1,
|
|
8
|
+
onDelete: "cascade"
|
|
9
|
+
}),
|
|
10
|
+
eventType: o(),
|
|
11
|
+
payload: r().nullable(),
|
|
12
|
+
occurredAt: s().default("now"),
|
|
13
|
+
stepName: o().nullable(),
|
|
14
|
+
attempt: n().nullable()
|
|
15
|
+
}).index(["runId", "occurredAt"]).index(["eventType"]);
|
|
16
|
+
//#endregion
|
|
17
|
+
export { c as _voltroWorkflowRunEventsTable };
|