@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,75 @@
|
|
|
1
|
+
import { Result as e, Schema as t } from "effect";
|
|
2
|
+
//#region src/cancelOnPlan.ts
|
|
3
|
+
var n = (e) => {
|
|
4
|
+
let t = e instanceof Error ? e.message : String(e);
|
|
5
|
+
return t.length > 400 ? `${t.slice(0, 400)}…` : t;
|
|
6
|
+
}, r = (r) => {
|
|
7
|
+
let i = [], a = [], o = [], s = /* @__PURE__ */ new Set(), c = /* @__PURE__ */ new Set(), l = r.payloadSchema === void 0 ? (t) => e.succeed(t) : (i) => {
|
|
8
|
+
let a = t.decodeUnknownResult(r.payloadSchema)(i);
|
|
9
|
+
return e.isSuccess(a) ? e.succeed(a.success) : e.fail(n(a.failure));
|
|
10
|
+
}, u = r.runs.map((e) => ({
|
|
11
|
+
run: e,
|
|
12
|
+
decoded: l(e.payload)
|
|
13
|
+
})), d = r.intents.map((e) => ({
|
|
14
|
+
intent: e,
|
|
15
|
+
decoded: l(e.payload)
|
|
16
|
+
}));
|
|
17
|
+
for (let l of r.entries) for (let f of r.events) {
|
|
18
|
+
if (f.name !== l.event) continue;
|
|
19
|
+
let p = t.decodeUnknownResult(l.schema)(f.payload);
|
|
20
|
+
if (e.isFailure(p)) {
|
|
21
|
+
o.push({
|
|
22
|
+
kind: "event-decode",
|
|
23
|
+
workflowName: r.workflowName,
|
|
24
|
+
event: l.event,
|
|
25
|
+
subject: f.id,
|
|
26
|
+
detail: n(p.failure)
|
|
27
|
+
});
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
let m = p.success, h = (e) => e.getTime() > f.occurredAt.getTime() ? !1 : l.withinMs === void 0 || f.occurredAt.getTime() - e.getTime() <= l.withinMs, g = (t, i) => {
|
|
31
|
+
if (e.isFailure(t)) return o.push({
|
|
32
|
+
kind: "payload-decode",
|
|
33
|
+
workflowName: r.workflowName,
|
|
34
|
+
event: l.event,
|
|
35
|
+
subject: i,
|
|
36
|
+
detail: t.failure
|
|
37
|
+
}), !1;
|
|
38
|
+
try {
|
|
39
|
+
return l.match(m, t.success) === !0;
|
|
40
|
+
} catch (e) {
|
|
41
|
+
return o.push({
|
|
42
|
+
kind: "match-threw",
|
|
43
|
+
workflowName: r.workflowName,
|
|
44
|
+
event: l.event,
|
|
45
|
+
subject: i,
|
|
46
|
+
detail: n(e)
|
|
47
|
+
}), !1;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
for (let { run: e, decoded: t } of u) s.has(e.runId) || h(e.startedAt) && g(t, e.runId) && (s.add(e.runId), i.push({
|
|
51
|
+
runId: e.runId,
|
|
52
|
+
executionId: e.executionId,
|
|
53
|
+
reason: l.reason,
|
|
54
|
+
event: l.event,
|
|
55
|
+
eventId: f.id
|
|
56
|
+
}));
|
|
57
|
+
for (let { intent: e, decoded: t } of d) c.has(e.intentId) || h(e.firstSeenAt) && g(t, e.intentId) && (c.add(e.intentId), a.push({
|
|
58
|
+
intentId: e.intentId,
|
|
59
|
+
reason: l.reason,
|
|
60
|
+
event: l.event,
|
|
61
|
+
eventId: f.id
|
|
62
|
+
}));
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
cancels: i,
|
|
66
|
+
discards: a,
|
|
67
|
+
problems: o
|
|
68
|
+
};
|
|
69
|
+
}, i = (e) => {
|
|
70
|
+
let t;
|
|
71
|
+
for (let n of e) (t === void 0 || n.occurredAt.getTime() > t.getTime()) && (t = n.occurredAt);
|
|
72
|
+
return t;
|
|
73
|
+
};
|
|
74
|
+
//#endregion
|
|
75
|
+
export { i as newestEventAt, r as planCancellations };
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { newestEventAt as e, planCancellations as t } from "./cancelOnPlan.js";
|
|
2
|
+
import { and as n, eq as r, gte as i } from "@voltro/database";
|
|
3
|
+
//#region src/cancelOnSweep.ts
|
|
4
|
+
var a = "_voltro_workflow_watermarks", o = "_voltro_workflow_events", s = "cancelOn", c = 36e5, l = 500, u = 2e3, d = (e) => {
|
|
5
|
+
if (e instanceof Date) return e;
|
|
6
|
+
if (typeof e == "number") return new Date(e);
|
|
7
|
+
if (typeof e == "string") {
|
|
8
|
+
let t = new Date(e);
|
|
9
|
+
if (!Number.isNaN(t.getTime())) return t;
|
|
10
|
+
}
|
|
11
|
+
}, f = (e) => e instanceof Error ? e.message : String(e), p = async (e, t) => d((await e.query({
|
|
12
|
+
table: a,
|
|
13
|
+
predicate: r("id", t),
|
|
14
|
+
order: [],
|
|
15
|
+
take: 1,
|
|
16
|
+
skip: void 0,
|
|
17
|
+
projection: void 0
|
|
18
|
+
}))[0]?.positionAt), m = async (e, t, n) => {
|
|
19
|
+
await e.upsert(a, {
|
|
20
|
+
id: t,
|
|
21
|
+
positionAt: n,
|
|
22
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
23
|
+
}, {
|
|
24
|
+
conflictColumns: ["id"],
|
|
25
|
+
update: (e) => {
|
|
26
|
+
let t = d(e.positionAt);
|
|
27
|
+
return t !== void 0 && t.getTime() >= n.getTime() ? {
|
|
28
|
+
positionAt: t,
|
|
29
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
30
|
+
} : {
|
|
31
|
+
positionAt: n,
|
|
32
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
}, h = async (e, t, i) => {
|
|
37
|
+
let a = async (a) => e.query({
|
|
38
|
+
table: "_voltro_workflow_runs",
|
|
39
|
+
predicate: n(r("tag", t), r("status", a)),
|
|
40
|
+
order: [{
|
|
41
|
+
column: "startedAt",
|
|
42
|
+
direction: "asc"
|
|
43
|
+
}],
|
|
44
|
+
take: i,
|
|
45
|
+
skip: void 0,
|
|
46
|
+
projection: void 0
|
|
47
|
+
});
|
|
48
|
+
return [...await a("running"), ...await a("suspended")].flatMap((e) => {
|
|
49
|
+
let t = e, n = d(t.startedAt);
|
|
50
|
+
return typeof t.id != "string" || typeof t.executionId != "string" || n === void 0 ? [] : [{
|
|
51
|
+
runId: t.id,
|
|
52
|
+
executionId: t.executionId,
|
|
53
|
+
payload: t.payload,
|
|
54
|
+
startedAt: n
|
|
55
|
+
}];
|
|
56
|
+
});
|
|
57
|
+
}, g = async (e, t, n) => (await e.query({
|
|
58
|
+
table: "_voltro_workflow_pending",
|
|
59
|
+
predicate: r("workflowName", t),
|
|
60
|
+
order: [{
|
|
61
|
+
column: "firstSeenAt",
|
|
62
|
+
direction: "asc"
|
|
63
|
+
}],
|
|
64
|
+
take: n,
|
|
65
|
+
skip: void 0,
|
|
66
|
+
projection: void 0
|
|
67
|
+
})).flatMap((e) => {
|
|
68
|
+
let t = e, n = d(t.firstSeenAt);
|
|
69
|
+
return typeof t.id != "string" || n === void 0 ? [] : [{
|
|
70
|
+
intentId: t.id,
|
|
71
|
+
payload: t.payload,
|
|
72
|
+
firstSeenAt: n
|
|
73
|
+
}];
|
|
74
|
+
}), _ = async (n, r) => {
|
|
75
|
+
let a = r.workflows.filter((e) => e.entries.length > 0);
|
|
76
|
+
if (a.length === 0) return {
|
|
77
|
+
examined: !1,
|
|
78
|
+
events: 0,
|
|
79
|
+
cancelled: 0,
|
|
80
|
+
discarded: 0,
|
|
81
|
+
catchingUp: !1,
|
|
82
|
+
sawFullRunPage: !1,
|
|
83
|
+
problems: [],
|
|
84
|
+
failures: [],
|
|
85
|
+
watermark: void 0
|
|
86
|
+
};
|
|
87
|
+
let c = n.now?.() ?? Date.now(), l = r.batch ?? 500, u = r.coldLookbackMs ?? 36e5, _ = /* @__PURE__ */ new Set();
|
|
88
|
+
for (let e of a) for (let t of e.entries) _.add(t.event);
|
|
89
|
+
let v = await p(n.store, s), y = v ?? new Date(c - u);
|
|
90
|
+
v === void 0 && (await m(n.store, s, y), v = y);
|
|
91
|
+
let b = await n.store.query({
|
|
92
|
+
table: o,
|
|
93
|
+
predicate: i("occurredAt", y),
|
|
94
|
+
order: [{
|
|
95
|
+
column: "occurredAt",
|
|
96
|
+
direction: "asc"
|
|
97
|
+
}],
|
|
98
|
+
take: l,
|
|
99
|
+
skip: void 0,
|
|
100
|
+
projection: void 0
|
|
101
|
+
}), x = [];
|
|
102
|
+
for (let e of b) {
|
|
103
|
+
let t = e, n = d(t.occurredAt);
|
|
104
|
+
typeof t.id == "string" && typeof t.name == "string" && n !== void 0 && _.has(t.name) && x.push({
|
|
105
|
+
id: t.id,
|
|
106
|
+
name: t.name,
|
|
107
|
+
payload: t.payload,
|
|
108
|
+
occurredAt: n
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
let S = [], C = [], w = 0, T = 0, E = !1, D = !1, O = r.runPage ?? 2e3;
|
|
112
|
+
if (x.length > 0) for (let e of a) {
|
|
113
|
+
let r = x.filter((t) => e.entries.some((e) => e.event === t.name));
|
|
114
|
+
if (r.length === 0) continue;
|
|
115
|
+
let i = [], a = [];
|
|
116
|
+
try {
|
|
117
|
+
i = await h(n.store, e.workflowName, O), a = await g(n.store, e.workflowName, O), (i.length >= O || a.length >= O) && (E = !0);
|
|
118
|
+
} catch (t) {
|
|
119
|
+
C.push({
|
|
120
|
+
subject: e.workflowName,
|
|
121
|
+
detail: f(t)
|
|
122
|
+
}), D = !0;
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
let o = t({
|
|
126
|
+
workflowName: e.workflowName,
|
|
127
|
+
entries: e.entries,
|
|
128
|
+
payloadSchema: e.payloadSchema,
|
|
129
|
+
events: r,
|
|
130
|
+
runs: i,
|
|
131
|
+
intents: a
|
|
132
|
+
});
|
|
133
|
+
S.push(...o.problems);
|
|
134
|
+
for (let t of o.cancels) try {
|
|
135
|
+
await n.cancelRun({
|
|
136
|
+
...t,
|
|
137
|
+
workflowName: e.workflowName
|
|
138
|
+
}), w += 1, n.log?.info("workflow.cancelOn: run cancelled", {
|
|
139
|
+
workflow: e.workflowName,
|
|
140
|
+
runId: t.runId,
|
|
141
|
+
event: t.event,
|
|
142
|
+
eventId: t.eventId
|
|
143
|
+
});
|
|
144
|
+
} catch (e) {
|
|
145
|
+
C.push({
|
|
146
|
+
subject: t.runId,
|
|
147
|
+
detail: f(e)
|
|
148
|
+
}), D = !0;
|
|
149
|
+
}
|
|
150
|
+
for (let t of o.discards) try {
|
|
151
|
+
await n.discardIntent({
|
|
152
|
+
...t,
|
|
153
|
+
workflowName: e.workflowName
|
|
154
|
+
}), T += 1;
|
|
155
|
+
} catch (e) {
|
|
156
|
+
C.push({
|
|
157
|
+
subject: t.intentId,
|
|
158
|
+
detail: f(e)
|
|
159
|
+
}), D = !0;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
let k = e(x), A = v;
|
|
163
|
+
if (D) n.log?.warn("workflow.cancelOn: holding the watermark — evaluation or delivery remains incomplete", { failures: C.length });
|
|
164
|
+
else if (k !== void 0) try {
|
|
165
|
+
await m(n.store, s, k), A = k;
|
|
166
|
+
} catch (e) {
|
|
167
|
+
C.push({
|
|
168
|
+
subject: s,
|
|
169
|
+
detail: f(e)
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
return S.length > 0 && n.log?.warn("workflow.cancelOn: some events could not be evaluated", {
|
|
173
|
+
count: S.length,
|
|
174
|
+
first: S[0]
|
|
175
|
+
}), {
|
|
176
|
+
examined: !0,
|
|
177
|
+
events: x.length,
|
|
178
|
+
cancelled: w,
|
|
179
|
+
discarded: T,
|
|
180
|
+
catchingUp: b.length >= l,
|
|
181
|
+
sawFullRunPage: E,
|
|
182
|
+
problems: S,
|
|
183
|
+
failures: C,
|
|
184
|
+
watermark: A
|
|
185
|
+
};
|
|
186
|
+
};
|
|
187
|
+
//#endregion
|
|
188
|
+
export { s as CANCEL_ON_WATERMARK, c as DEFAULT_COLD_LOOKBACK_MS, l as DEFAULT_EVENT_BATCH, u as DEFAULT_RUN_PAGE, o as EVENTS_TABLE, a as WATERMARKS_TABLE, p as readWatermark, _ as sweepCancelOn, m as writeWatermark };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { readAdmissionSubmission as e } from "./admissionSubmission.js";
|
|
2
|
+
import { readWorkflowStartReceipt as t, settlePendingStartReceipts as n } from "./startReceipt.js";
|
|
3
|
+
import { PENDING_TABLE as r, toPendingIntent as i } from "./admissionStore.js";
|
|
4
|
+
import { eq as a } from "@voltro/database";
|
|
5
|
+
//#region src/cancelPendingStart.ts
|
|
6
|
+
var o = async (o, s) => {
|
|
7
|
+
if (!Number.isFinite(s.now) || !Number.isFinite(new Date(s.now).getTime())) throw Error("Queued cancellation requires a valid timestamp");
|
|
8
|
+
let c = await t(o, s.receiptId);
|
|
9
|
+
if (c === void 0 || c.workflowName !== s.workflowName || c.tenantId !== s.tenantId) throw Error("Queued cancellation receipt is missing or belongs to another workflow or tenant");
|
|
10
|
+
if (c.terminal !== null) return {
|
|
11
|
+
kind: "terminal",
|
|
12
|
+
outcome: c.terminal
|
|
13
|
+
};
|
|
14
|
+
if (c.submissionId !== null) {
|
|
15
|
+
let t = await e(o, c.submissionId);
|
|
16
|
+
if (t === void 0 || !t.receiptsBound || t.workflowName !== c.workflowName || t.tenantId !== c.tenantId || !t.intentIds.includes(c.pendingId)) throw Error("Queued cancellation receipt has no matching submission");
|
|
17
|
+
return {
|
|
18
|
+
kind: "submitted",
|
|
19
|
+
submissionId: t.id
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
let [l] = await o.query({
|
|
23
|
+
table: r,
|
|
24
|
+
predicate: a("id", c.pendingId),
|
|
25
|
+
lock: "update",
|
|
26
|
+
order: [],
|
|
27
|
+
take: 1,
|
|
28
|
+
skip: void 0,
|
|
29
|
+
projection: void 0
|
|
30
|
+
});
|
|
31
|
+
if (l === void 0) throw Error("Queued cancellation has no pending input or submission");
|
|
32
|
+
let u = i(l);
|
|
33
|
+
if (u.workflowName !== c.workflowName || u.tenantId !== c.tenantId || u.deadLetteredAt !== void 0) throw Error("Queued cancellation input has contradictory ownership or is dead-lettered");
|
|
34
|
+
let d = {
|
|
35
|
+
kind: "cancelled",
|
|
36
|
+
at: s.now
|
|
37
|
+
};
|
|
38
|
+
if (await n(o, {
|
|
39
|
+
pendingId: c.pendingId,
|
|
40
|
+
workflowName: c.workflowName,
|
|
41
|
+
tenantId: c.tenantId,
|
|
42
|
+
terminal: d
|
|
43
|
+
}), !await o.delete("_voltro_workflow_pending", c.pendingId)) throw Error("Queued cancellation lost its pending input");
|
|
44
|
+
return {
|
|
45
|
+
kind: "terminal",
|
|
46
|
+
outcome: d
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
//#endregion
|
|
50
|
+
export { o as cancelPendingWorkflowStartInTransaction };
|