@voltro/workflow 0.86.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 +5321 -0
- package/THIRD-PARTY-NOTICES.md +1130 -11
- package/dist/cluster.d.ts +111 -27
- package/dist/cluster.js +12 -8
- package/dist/clusterCron.js +17 -9
- package/dist/clusterLayer.js +104 -69
- package/dist/clusterRunnerLayer.js +26 -16
- package/dist/clusterShardGroups.js +33 -0
- package/dist/clusterTestSuite.d.ts +23 -0
- package/dist/clusterTestSuite.js +142 -112
- package/dist/index.d.ts +47 -22
- package/dist/index.js +24 -23
- 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/workflowExecutorRouting.js +33 -0
- package/dist/workflowRestartDispatch.js +29 -23
- package/dist/workflowRestartReservation.js +156 -155
- package/dist/workflowResumeDispatch.js +17 -16
- package/dist/workflowRuntimeReadiness.js +12 -0
- package/dist/workflowShardRelocation.js +58 -0
- package/dist/workflowShardRelocationSql.js +72 -0
- package/package.json +4 -4
|
@@ -1,50 +1,51 @@
|
|
|
1
1
|
import { resolveAdmissionKeys as e } from "./admission.js";
|
|
2
2
|
import { decodePendingPayload as t, evaluateAdmission as n, recordAdmission as r } from "./admissionStore.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
3
|
+
import { ownedJournalRoutingPromise as i } from "./journalRoutingGuard.js";
|
|
4
|
+
import { resetExpectedWorkflowReplies as a } from "./workflowJournalReset.js";
|
|
5
|
+
import { Effect as o, Schema as s } from "effect";
|
|
6
|
+
import { WorkflowRestartObservationSchema as c, WorkflowRestartSelectionSchema as l, WorkflowRestartTargetSchema as u } from "@voltro/protocol";
|
|
7
|
+
import { and as d, derivedRowId as f, eq as p, id as m, integer as h, json as g, or as _, table as v, text as y, timestamp as b } from "@voltro/database";
|
|
7
8
|
//#region src/workflowRestartReservation.ts
|
|
8
|
-
var
|
|
9
|
-
id:
|
|
10
|
-
runId:
|
|
11
|
-
workflowName:
|
|
12
|
-
executionId:
|
|
13
|
-
generation:
|
|
14
|
-
token:
|
|
15
|
-
ledgerId:
|
|
16
|
-
tenantId:
|
|
17
|
-
delivery:
|
|
18
|
-
replies:
|
|
19
|
-
selection:
|
|
20
|
-
eviction:
|
|
21
|
-
requestedAt:
|
|
22
|
-
dispatchAttempts:
|
|
23
|
-
enteredGeneration:
|
|
24
|
-
}).unique(["runId", "generation"]).unique(["runId", "token"]).nonReactive(),
|
|
25
|
-
requestId:
|
|
26
|
-
restartToken:
|
|
27
|
-
}),
|
|
28
|
-
requestId:
|
|
29
|
-
replyId:
|
|
30
|
-
}),
|
|
31
|
-
id:
|
|
32
|
-
runId:
|
|
33
|
-
workflowName:
|
|
34
|
-
tenantId:
|
|
35
|
-
selection:
|
|
36
|
-
withdrawnAt:
|
|
37
|
-
}).nonReactive(),
|
|
38
|
-
id:
|
|
39
|
-
runId:
|
|
40
|
-
workflowName:
|
|
41
|
-
tenantId:
|
|
42
|
-
selection:
|
|
43
|
-
withdrawnAt:
|
|
44
|
-
}),
|
|
45
|
-
let n =
|
|
46
|
-
table:
|
|
47
|
-
predicate:
|
|
9
|
+
var x = v("_voltro_workflow_restart_requests", {
|
|
10
|
+
id: m({ prefix: "wfrs" }),
|
|
11
|
+
runId: y(),
|
|
12
|
+
workflowName: y(),
|
|
13
|
+
executionId: y(),
|
|
14
|
+
generation: y(),
|
|
15
|
+
token: y(),
|
|
16
|
+
ledgerId: y(),
|
|
17
|
+
tenantId: y().nullable(),
|
|
18
|
+
delivery: g(),
|
|
19
|
+
replies: g(),
|
|
20
|
+
selection: g().nullable(),
|
|
21
|
+
eviction: g().nullable(),
|
|
22
|
+
requestedAt: b(),
|
|
23
|
+
dispatchAttempts: h().default(0),
|
|
24
|
+
enteredGeneration: y().nullable()
|
|
25
|
+
}).unique(["runId", "generation"]).unique(["runId", "token"]).nonReactive(), S = s.NonEmptyString, C = s.Struct({
|
|
26
|
+
requestId: S,
|
|
27
|
+
restartToken: s.NullOr(S)
|
|
28
|
+
}), w = s.Struct({
|
|
29
|
+
requestId: S,
|
|
30
|
+
replyId: S
|
|
31
|
+
}), T = l, E = v("_voltro_workflow_restart_withdrawals", {
|
|
32
|
+
id: m({ prefix: "wfrw" }),
|
|
33
|
+
runId: y(),
|
|
34
|
+
workflowName: y(),
|
|
35
|
+
tenantId: y().nullable(),
|
|
36
|
+
selection: g(),
|
|
37
|
+
withdrawnAt: b()
|
|
38
|
+
}).nonReactive(), D = s.Struct({
|
|
39
|
+
id: s.NonEmptyString,
|
|
40
|
+
runId: s.NonEmptyString,
|
|
41
|
+
workflowName: s.NonEmptyString,
|
|
42
|
+
tenantId: s.NullOr(s.NonEmptyString),
|
|
43
|
+
selection: T,
|
|
44
|
+
withdrawnAt: s.Date
|
|
45
|
+
}), O = async (e, t) => {
|
|
46
|
+
let n = s.decodeUnknownSync(u)(t), [r] = await e.query({
|
|
47
|
+
table: E.tableName,
|
|
48
|
+
predicate: p("id", n.requestId),
|
|
48
49
|
lock: "update",
|
|
49
50
|
order: [],
|
|
50
51
|
take: 1,
|
|
@@ -52,35 +53,35 @@ var b = _("_voltro_workflow_restart_requests", {
|
|
|
52
53
|
projection: void 0
|
|
53
54
|
});
|
|
54
55
|
if (r === void 0) return;
|
|
55
|
-
let i =
|
|
56
|
+
let i = s.decodeUnknownSync(D)(r);
|
|
56
57
|
if (i.runId !== n.runId) throw Error("Restart identity belongs to a different command");
|
|
57
58
|
if (!Number.isFinite(i.withdrawnAt.getTime())) throw Error("Invalid restart withdrawal timestamp");
|
|
58
59
|
return i;
|
|
59
|
-
},
|
|
60
|
-
if (await
|
|
61
|
-
},
|
|
62
|
-
id:
|
|
63
|
-
runId:
|
|
64
|
-
workflowName:
|
|
65
|
-
executionId:
|
|
66
|
-
generation:
|
|
67
|
-
token:
|
|
68
|
-
ledgerId:
|
|
69
|
-
tenantId:
|
|
70
|
-
delivery:
|
|
71
|
-
replies:
|
|
72
|
-
selection:
|
|
73
|
-
eviction:
|
|
74
|
-
executionId:
|
|
75
|
-
runId:
|
|
60
|
+
}, k = async (e, t) => {
|
|
61
|
+
if (await O(e, t) !== void 0) throw Error("Restart request was permanently withdrawn");
|
|
62
|
+
}, A = s.Struct({
|
|
63
|
+
id: S,
|
|
64
|
+
runId: S,
|
|
65
|
+
workflowName: S,
|
|
66
|
+
executionId: S,
|
|
67
|
+
generation: S,
|
|
68
|
+
token: S,
|
|
69
|
+
ledgerId: S,
|
|
70
|
+
tenantId: s.NullOr(S),
|
|
71
|
+
delivery: C,
|
|
72
|
+
replies: s.Array(w),
|
|
73
|
+
selection: T,
|
|
74
|
+
eviction: s.NullOr(s.Struct({
|
|
75
|
+
executionId: S,
|
|
76
|
+
runId: s.String
|
|
76
77
|
})),
|
|
77
|
-
requestedAt:
|
|
78
|
-
dispatchAttempts:
|
|
79
|
-
enteredGeneration:
|
|
80
|
-
}),
|
|
81
|
-
let n =
|
|
82
|
-
table:
|
|
83
|
-
predicate:
|
|
78
|
+
requestedAt: s.Date,
|
|
79
|
+
dispatchAttempts: s.Number.check(s.isInt(), s.isGreaterThanOrEqualTo(0)),
|
|
80
|
+
enteredGeneration: s.NullOr(S)
|
|
81
|
+
}), j = (e, t) => e.kind === t.kind && (e.kind === "failed-steps" || t.kind === "from-step" && e.stepName === t.stepName), M = async (e, t) => {
|
|
82
|
+
let n = s.decodeUnknownSync(u)(t), [r] = await e.query({
|
|
83
|
+
table: x.tableName,
|
|
84
|
+
predicate: p("id", n.requestId),
|
|
84
85
|
lock: "update",
|
|
85
86
|
order: [],
|
|
86
87
|
take: 1,
|
|
@@ -88,20 +89,20 @@ var b = _("_voltro_workflow_restart_requests", {
|
|
|
88
89
|
projection: void 0
|
|
89
90
|
});
|
|
90
91
|
if (r === void 0) return;
|
|
91
|
-
let i =
|
|
92
|
+
let i = s.decodeUnknownSync(A)(r);
|
|
92
93
|
if (i.runId !== n.runId) throw Error("Restart identity belongs to a different command");
|
|
93
94
|
return i;
|
|
94
|
-
},
|
|
95
|
-
let n = await
|
|
96
|
-
if (n !== void 0) return
|
|
95
|
+
}, N = async (e, t) => {
|
|
96
|
+
let n = await O(e, t);
|
|
97
|
+
if (n !== void 0) return s.decodeUnknownSync(c)({
|
|
97
98
|
...t,
|
|
98
99
|
kind: "withdrawn",
|
|
99
100
|
workflowName: n.workflowName,
|
|
100
101
|
selection: n.selection,
|
|
101
102
|
withdrawnAt: n.withdrawnAt.getTime()
|
|
102
103
|
});
|
|
103
|
-
let r = await
|
|
104
|
-
if (r === void 0) return
|
|
104
|
+
let r = await M(e, t);
|
|
105
|
+
if (r === void 0) return s.decodeUnknownSync(c)({
|
|
105
106
|
...t,
|
|
106
107
|
kind: "not-found"
|
|
107
108
|
});
|
|
@@ -115,7 +116,7 @@ var b = _("_voltro_workflow_restart_requests", {
|
|
|
115
116
|
requestedAt: r.requestedAt.getTime(),
|
|
116
117
|
dispatchAttempts: r.dispatchAttempts
|
|
117
118
|
};
|
|
118
|
-
return
|
|
119
|
+
return s.decodeUnknownSync(c)(r.enteredGeneration === null ? {
|
|
119
120
|
...i,
|
|
120
121
|
kind: "pending"
|
|
121
122
|
} : {
|
|
@@ -123,56 +124,56 @@ var b = _("_voltro_workflow_restart_requests", {
|
|
|
123
124
|
kind: "entered",
|
|
124
125
|
enteredGeneration: r.enteredGeneration
|
|
125
126
|
});
|
|
126
|
-
},
|
|
127
|
+
}, P = async (e, t) => {
|
|
127
128
|
for (let e of [
|
|
128
129
|
t.id,
|
|
129
130
|
t.runId,
|
|
130
131
|
t.workflowName
|
|
131
|
-
])
|
|
132
|
+
]) s.decodeUnknownSync(S)(e);
|
|
132
133
|
if (t.id.length > 64) throw Error("Invalid restart request identity");
|
|
133
|
-
|
|
134
|
-
let n =
|
|
135
|
-
await
|
|
134
|
+
s.decodeUnknownSync(s.NullOr(S))(t.tenantId);
|
|
135
|
+
let n = s.decodeUnknownSync(T)(t.selection);
|
|
136
|
+
await k(e, {
|
|
136
137
|
requestId: t.id,
|
|
137
138
|
runId: t.runId
|
|
138
139
|
});
|
|
139
|
-
let r = await
|
|
140
|
+
let r = await M(e, {
|
|
140
141
|
requestId: t.id,
|
|
141
142
|
runId: t.runId
|
|
142
143
|
});
|
|
143
144
|
if (r !== void 0) {
|
|
144
|
-
if (r.runId !== t.runId || r.workflowName !== t.workflowName || r.tenantId !== t.tenantId || !
|
|
145
|
+
if (r.runId !== t.runId || r.workflowName !== t.workflowName || r.tenantId !== t.tenantId || !j(r.selection, n)) throw Error("Restart identity belongs to a different command");
|
|
145
146
|
return r;
|
|
146
147
|
}
|
|
147
|
-
},
|
|
148
|
-
let n =
|
|
148
|
+
}, F = async (e, t) => {
|
|
149
|
+
let n = s.decodeUnknownSync(D)({
|
|
149
150
|
...t,
|
|
150
151
|
withdrawnAt: new Date(t.now)
|
|
151
152
|
});
|
|
152
|
-
if (
|
|
153
|
+
if (s.decodeUnknownSync(u)({
|
|
153
154
|
requestId: n.id,
|
|
154
155
|
runId: n.runId
|
|
155
156
|
}), !Number.isFinite(n.withdrawnAt.getTime())) throw Error("Invalid restart withdrawal timestamp");
|
|
156
|
-
let r = await
|
|
157
|
+
let r = await O(e, {
|
|
157
158
|
requestId: n.id,
|
|
158
159
|
runId: n.runId
|
|
159
160
|
});
|
|
160
161
|
if (r !== void 0) {
|
|
161
|
-
if (r.workflowName !== n.workflowName || r.tenantId !== n.tenantId || !
|
|
162
|
+
if (r.workflowName !== n.workflowName || r.tenantId !== n.tenantId || !j(r.selection, n.selection)) throw Error("Restart identity belongs to a different command");
|
|
162
163
|
return {
|
|
163
164
|
kind: "withdrawn",
|
|
164
165
|
withdrawal: r,
|
|
165
166
|
reused: !0
|
|
166
167
|
};
|
|
167
168
|
}
|
|
168
|
-
let i = await
|
|
169
|
+
let i = await P(e, n);
|
|
169
170
|
if (i !== void 0) return {
|
|
170
171
|
kind: "reserved",
|
|
171
172
|
request: i
|
|
172
173
|
};
|
|
173
174
|
let [a] = await e.query({
|
|
174
175
|
table: "_voltro_workflow_runs",
|
|
175
|
-
predicate:
|
|
176
|
+
predicate: p("id", n.runId),
|
|
176
177
|
lock: "update",
|
|
177
178
|
order: [],
|
|
178
179
|
take: 1,
|
|
@@ -180,49 +181,49 @@ var b = _("_voltro_workflow_restart_requests", {
|
|
|
180
181
|
projection: void 0
|
|
181
182
|
});
|
|
182
183
|
if (a === void 0 || a.tag !== n.workflowName) throw Error("Restart withdrawal requires its resident workflow");
|
|
183
|
-
if ((
|
|
184
|
-
return await e.insert(
|
|
184
|
+
if ((s.decodeUnknownSync(s.NullOr(s.Struct({ tenantId: s.NullOr(S) })))(a.subject ?? null)?.tenantId ?? null) !== n.tenantId) throw Error("Restart withdrawal belongs to another resident tenant");
|
|
185
|
+
return await e.insert(E.tableName, n), {
|
|
185
186
|
kind: "withdrawn",
|
|
186
187
|
withdrawal: n,
|
|
187
188
|
reused: !1
|
|
188
189
|
};
|
|
189
|
-
},
|
|
190
|
-
|
|
191
|
-
let n = await
|
|
190
|
+
}, I = async (e, t) => {
|
|
191
|
+
s.decodeUnknownSync(S)(t.generation);
|
|
192
|
+
let n = await P(e, t);
|
|
192
193
|
if (n !== void 0 && n.generation !== t.generation) throw Error("Restart identity belongs to a different command");
|
|
193
194
|
return n;
|
|
194
|
-
},
|
|
195
|
+
}, L = async (i, a) => {
|
|
195
196
|
for (let e of [
|
|
196
197
|
a.id,
|
|
197
198
|
a.runId,
|
|
198
199
|
a.generation,
|
|
199
200
|
a.token
|
|
200
|
-
])
|
|
201
|
+
]) s.decodeUnknownSync(S)(e);
|
|
201
202
|
if (a.id.length > 64 || !Number.isFinite(new Date(a.now).getTime())) throw Error("Invalid restart request identity or timestamp");
|
|
202
|
-
await
|
|
203
|
+
await k(i, {
|
|
203
204
|
requestId: a.id,
|
|
204
205
|
runId: a.runId
|
|
205
206
|
});
|
|
206
|
-
let
|
|
207
|
-
if (
|
|
208
|
-
let l =
|
|
207
|
+
let o = s.decodeUnknownSync(C)(a.delivery), c = s.decodeUnknownSync(T)(a.selection);
|
|
208
|
+
if (o.restartToken === a.token) throw Error("Restart requires a new delivery token");
|
|
209
|
+
let l = s.decodeUnknownSync(s.Array(w))(a.replies), u = /* @__PURE__ */ new Map();
|
|
209
210
|
for (let e of l) {
|
|
210
|
-
if (!/^[1-9]\d*$/.test(e.requestId) || !/^[1-9]\d*$/.test(e.replyId) ||
|
|
211
|
-
|
|
211
|
+
if (!/^[1-9]\d*$/.test(e.requestId) || !/^[1-9]\d*$/.test(e.replyId) || u.has(e.requestId)) throw Error("Restart requires distinct, exact journal reply identities");
|
|
212
|
+
u.set(e.requestId, e.replyId);
|
|
212
213
|
}
|
|
213
|
-
if (!
|
|
214
|
-
let [
|
|
215
|
-
table:
|
|
216
|
-
predicate:
|
|
214
|
+
if (!u.has(o.requestId)) throw Error("Restart selection must include its run reply");
|
|
215
|
+
let [f] = await i.query({
|
|
216
|
+
table: x.tableName,
|
|
217
|
+
predicate: p("id", a.id),
|
|
217
218
|
lock: "update",
|
|
218
219
|
order: [],
|
|
219
220
|
take: 1,
|
|
220
221
|
skip: void 0,
|
|
221
222
|
projection: void 0
|
|
222
223
|
});
|
|
223
|
-
if (
|
|
224
|
-
let e =
|
|
225
|
-
if (e.runId !== a.runId || e.generation !== a.generation || e.token !== a.token || e.workflowName !== a.control.workflowName || e.tenantId !== a.tenantId || e.delivery.requestId !==
|
|
224
|
+
if (f !== void 0) {
|
|
225
|
+
let e = s.decodeUnknownSync(A)(f);
|
|
226
|
+
if (e.runId !== a.runId || e.generation !== a.generation || e.token !== a.token || e.workflowName !== a.control.workflowName || e.tenantId !== a.tenantId || e.delivery.requestId !== o.requestId || e.delivery.restartToken !== o.restartToken || !j(e.selection, c) || e.replies.length !== u.size || e.replies.some((e) => u.get(e.requestId) !== e.replyId)) throw Error("Restart identity belongs to a different request");
|
|
226
227
|
return {
|
|
227
228
|
kind: "reserved",
|
|
228
229
|
request: e,
|
|
@@ -231,7 +232,7 @@ var b = _("_voltro_workflow_restart_requests", {
|
|
|
231
232
|
}
|
|
232
233
|
let [m] = await i.query({
|
|
233
234
|
table: "_voltro_workflow_runs",
|
|
234
|
-
predicate:
|
|
235
|
+
predicate: p("id", a.runId),
|
|
235
236
|
lock: "update",
|
|
236
237
|
order: [],
|
|
237
238
|
take: 1,
|
|
@@ -239,23 +240,23 @@ var b = _("_voltro_workflow_restart_requests", {
|
|
|
239
240
|
projection: void 0
|
|
240
241
|
});
|
|
241
242
|
if (m === void 0 || m.tag !== a.control.workflowName || m.runnerGeneration !== a.generation || m.status !== "failed" || m.discardedAt != null || typeof m.executionId != "string" || m.executionId.length === 0) throw Error("Restart requires its undiscarded failed resident generation");
|
|
242
|
-
if ((
|
|
243
|
-
let h =
|
|
244
|
-
if (h.requestId !==
|
|
245
|
-
let [
|
|
246
|
-
table:
|
|
247
|
-
predicate:
|
|
243
|
+
if ((s.decodeUnknownSync(s.NullOr(s.Struct({ tenantId: s.NullOr(S) })))(m.subject ?? null)?.tenantId ?? null) !== a.tenantId) throw Error("Restart belongs to another resident tenant");
|
|
244
|
+
let h = s.decodeUnknownSync(C)(m.engineDelivery);
|
|
245
|
+
if (h.requestId !== o.requestId || h.restartToken !== o.restartToken) throw Error("Restart journal delivery does not belong to its resident generation");
|
|
246
|
+
let [g] = await i.query({
|
|
247
|
+
table: x.tableName,
|
|
248
|
+
predicate: d(p("runId", a.runId), _(p("generation", a.generation), p("token", a.token))),
|
|
248
249
|
lock: "update",
|
|
249
250
|
order: [],
|
|
250
251
|
take: 1,
|
|
251
252
|
skip: void 0,
|
|
252
253
|
projection: ["id", "generation"]
|
|
253
254
|
});
|
|
254
|
-
if (
|
|
255
|
-
if (
|
|
255
|
+
if (g !== void 0) {
|
|
256
|
+
if (g.generation !== a.generation) throw Error("Restart delivery token was already used by this run");
|
|
256
257
|
return { kind: "already-requested" };
|
|
257
258
|
}
|
|
258
|
-
let v = t(i, a.control.workflowName, m.payload), y = e(a.control, v),
|
|
259
|
+
let v = t(i, a.control.workflowName, m.payload), y = e(a.control, v), b = await n({
|
|
259
260
|
store: i,
|
|
260
261
|
control: a.control,
|
|
261
262
|
keys: y,
|
|
@@ -263,9 +264,9 @@ var b = _("_voltro_workflow_restart_requests", {
|
|
|
263
264
|
now: a.now,
|
|
264
265
|
reconsidering: !0
|
|
265
266
|
});
|
|
266
|
-
if (
|
|
267
|
+
if (b.kind !== "admit") return {
|
|
267
268
|
kind: "not-admitted",
|
|
268
|
-
decision:
|
|
269
|
+
decision: b
|
|
269
270
|
};
|
|
270
271
|
let E = await r({
|
|
271
272
|
store: i,
|
|
@@ -273,7 +274,7 @@ var b = _("_voltro_workflow_restart_requests", {
|
|
|
273
274
|
keys: y,
|
|
274
275
|
outcome: "admitted",
|
|
275
276
|
mode: "restart",
|
|
276
|
-
reason:
|
|
277
|
+
reason: b.reason,
|
|
277
278
|
collapsed: 1,
|
|
278
279
|
waitedMs: 0,
|
|
279
280
|
executionId: null,
|
|
@@ -282,7 +283,7 @@ var b = _("_voltro_workflow_restart_requests", {
|
|
|
282
283
|
now: a.now
|
|
283
284
|
});
|
|
284
285
|
if (E === void 0) throw Error("Restart has no admission reservation");
|
|
285
|
-
let D =
|
|
286
|
+
let D = s.decodeUnknownSync(A)({
|
|
286
287
|
id: a.id,
|
|
287
288
|
runId: a.runId,
|
|
288
289
|
workflowName: a.control.workflowName,
|
|
@@ -291,23 +292,23 @@ var b = _("_voltro_workflow_restart_requests", {
|
|
|
291
292
|
token: a.token,
|
|
292
293
|
ledgerId: E,
|
|
293
294
|
tenantId: a.tenantId,
|
|
294
|
-
delivery:
|
|
295
|
+
delivery: o,
|
|
295
296
|
replies: l,
|
|
296
297
|
selection: c,
|
|
297
|
-
eviction:
|
|
298
|
+
eviction: b.evict ?? null,
|
|
298
299
|
requestedAt: new Date(a.now),
|
|
299
300
|
dispatchAttempts: 0,
|
|
300
301
|
enteredGeneration: null
|
|
301
302
|
});
|
|
302
|
-
return await i.insert(
|
|
303
|
+
return await i.insert(x.tableName, D), {
|
|
303
304
|
kind: "reserved",
|
|
304
305
|
request: D,
|
|
305
306
|
reused: !1
|
|
306
307
|
};
|
|
307
|
-
},
|
|
308
|
+
}, R = async (e, t) => {
|
|
308
309
|
let [n] = await e.query({
|
|
309
|
-
table:
|
|
310
|
-
predicate:
|
|
310
|
+
table: x.tableName,
|
|
311
|
+
predicate: p("id", t),
|
|
311
312
|
lock: "update",
|
|
312
313
|
order: [],
|
|
313
314
|
take: 1,
|
|
@@ -315,11 +316,11 @@ var b = _("_voltro_workflow_restart_requests", {
|
|
|
315
316
|
projection: void 0
|
|
316
317
|
});
|
|
317
318
|
if (n === void 0) throw Error("Restart dispatch has no resident request");
|
|
318
|
-
let r =
|
|
319
|
+
let r = s.decodeUnknownSync(A)(n);
|
|
319
320
|
if (r.enteredGeneration !== null) throw Error("Restart request has already entered its resident generation");
|
|
320
321
|
let [i] = await e.query({
|
|
321
322
|
table: "_voltro_workflow_admissions",
|
|
322
|
-
predicate:
|
|
323
|
+
predicate: p("id", r.ledgerId),
|
|
323
324
|
lock: "update",
|
|
324
325
|
order: [],
|
|
325
326
|
take: 1,
|
|
@@ -329,7 +330,7 @@ var b = _("_voltro_workflow_restart_requests", {
|
|
|
329
330
|
if (i === void 0 || i.outcome !== "admitted" || i.releasedAt !== null || i.workflowName !== r.workflowName || i.tenantId !== r.tenantId || i.executionId !== null || i.runId !== null) throw Error("Restart dispatch has no matching held resident reservation");
|
|
330
331
|
let [a] = await e.query({
|
|
331
332
|
table: "_voltro_workflow_runs",
|
|
332
|
-
predicate:
|
|
333
|
+
predicate: p("id", r.runId),
|
|
333
334
|
lock: "update",
|
|
334
335
|
order: [],
|
|
335
336
|
take: 1,
|
|
@@ -337,44 +338,44 @@ var b = _("_voltro_workflow_restart_requests", {
|
|
|
337
338
|
projection: void 0
|
|
338
339
|
});
|
|
339
340
|
if (a === void 0 || a.tag !== r.workflowName || a.executionId !== r.executionId || a.runnerGeneration !== r.generation || a.status !== "failed" || a.discardedAt != null) throw Error("Restart dispatch no longer owns its failed resident generation");
|
|
340
|
-
let
|
|
341
|
-
if (
|
|
341
|
+
let o = s.decodeUnknownSync(C)(a.engineDelivery);
|
|
342
|
+
if (o.requestId !== r.delivery.requestId || o.restartToken !== r.delivery.restartToken) throw Error("Restart dispatch no longer owns its journal delivery");
|
|
342
343
|
return {
|
|
343
344
|
request: r,
|
|
344
345
|
run: a
|
|
345
346
|
};
|
|
346
|
-
},
|
|
347
|
-
let { request: n } = await
|
|
347
|
+
}, z = async (e, t) => {
|
|
348
|
+
let { request: n } = await R(e, t), r = n.dispatchAttempts + 1;
|
|
348
349
|
if (!Number.isSafeInteger(r)) throw Error("Restart dispatch attempt counter exhausted");
|
|
349
|
-
if (await e.update(
|
|
350
|
+
if (await e.update(x.tableName, t, { dispatchAttempts: r }) === null) throw Error("Restart request disappeared before dispatch");
|
|
350
351
|
return {
|
|
351
352
|
...n,
|
|
352
353
|
dispatchAttempts: r
|
|
353
354
|
};
|
|
354
|
-
},
|
|
355
|
-
let { request: t } = yield*
|
|
356
|
-
if (!(yield*
|
|
357
|
-
let n = yield*
|
|
358
|
-
return yield*
|
|
355
|
+
}, B = (e) => o.gen(function* () {
|
|
356
|
+
let { request: t } = yield* i(() => e.transaction((t) => R(t, e.requestId)));
|
|
357
|
+
if (!(yield* i(() => e.acquireCapacity(t)))) return { kind: "waiting-capacity" };
|
|
358
|
+
let n = yield* i(() => e.transaction((e) => z(e, t.id)));
|
|
359
|
+
return yield* a(n.replies, {
|
|
359
360
|
requestId: n.delivery.requestId,
|
|
360
361
|
previousToken: n.delivery.restartToken,
|
|
361
362
|
token: n.token,
|
|
362
363
|
workflowName: n.workflowName,
|
|
363
364
|
executionId: n.executionId
|
|
364
365
|
});
|
|
365
|
-
}),
|
|
366
|
+
}), V = async (e, t) => {
|
|
366
367
|
for (let e of [
|
|
367
368
|
t.runId,
|
|
368
369
|
t.workflowName,
|
|
369
370
|
t.executionId,
|
|
370
371
|
t.generation
|
|
371
|
-
])
|
|
372
|
+
]) s.decodeUnknownSync(S)(e);
|
|
372
373
|
if (!Number.isFinite(new Date(t.now).getTime())) throw Error("Restart entry requires a valid timestamp");
|
|
373
|
-
let n =
|
|
374
|
+
let n = s.decodeUnknownSync(C)(t.delivery);
|
|
374
375
|
if (n.restartToken === null) throw Error("Restart entry has no delivery token");
|
|
375
376
|
let [r] = await e.query({
|
|
376
|
-
table:
|
|
377
|
-
predicate:
|
|
377
|
+
table: x.tableName,
|
|
378
|
+
predicate: d(p("runId", t.runId), p("token", n.restartToken)),
|
|
378
379
|
lock: "update",
|
|
379
380
|
order: [],
|
|
380
381
|
take: 1,
|
|
@@ -382,15 +383,15 @@ var b = _("_voltro_workflow_restart_requests", {
|
|
|
382
383
|
projection: ["id"]
|
|
383
384
|
});
|
|
384
385
|
if (r === void 0) throw Error("Restart delivery has no matching resident request");
|
|
385
|
-
let { request: i, run: a } = await
|
|
386
|
+
let { request: i, run: a } = await R(e, s.decodeUnknownSync(S)(r.id));
|
|
386
387
|
if (i.runId !== t.runId || i.workflowName !== t.workflowName || i.executionId !== t.executionId || i.generation === t.generation || i.delivery.requestId !== n.requestId || i.token !== n.restartToken) throw Error("Restart entry does not match its reserved delivery");
|
|
387
388
|
if (i.dispatchAttempts === 0) throw Error("Restart entry has no committed dispatch attempt");
|
|
388
389
|
if (await e.update("_voltro_workflow_admissions", i.ledgerId, {
|
|
389
390
|
executionId: i.executionId,
|
|
390
391
|
runId: i.runId
|
|
391
392
|
}) === null) throw Error("Restart reservation disappeared during entry");
|
|
392
|
-
if (await e.update(
|
|
393
|
-
let
|
|
393
|
+
if (await e.update(x.tableName, i.id, { enteredGeneration: t.generation }) === null) throw Error("Restart request disappeared during entry");
|
|
394
|
+
let o = await e.update("_voltro_workflow_runs", i.runId, {
|
|
394
395
|
runnerGeneration: t.generation,
|
|
395
396
|
engineDelivery: n,
|
|
396
397
|
runnerEnteredAt: new Date(t.now),
|
|
@@ -402,12 +403,12 @@ var b = _("_voltro_workflow_restart_requests", {
|
|
|
402
403
|
completedAt: null,
|
|
403
404
|
durationMs: null
|
|
404
405
|
});
|
|
405
|
-
if (
|
|
406
|
+
if (o === null) throw Error("Restart run disappeared during entry");
|
|
406
407
|
return {
|
|
407
|
-
row:
|
|
408
|
+
row: o,
|
|
408
409
|
previous: a,
|
|
409
410
|
event: await e.insert("_voltro_workflow_run_events", {
|
|
410
|
-
id:
|
|
411
|
+
id: f("wfev", JSON.stringify(["restart", i.id])),
|
|
411
412
|
runId: i.runId,
|
|
412
413
|
eventType: "run-redriven",
|
|
413
414
|
occurredAt: new Date(t.now),
|
|
@@ -423,4 +424,4 @@ var b = _("_voltro_workflow_restart_requests", {
|
|
|
423
424
|
};
|
|
424
425
|
};
|
|
425
426
|
//#endregion
|
|
426
|
-
export {
|
|
427
|
+
export { z as beginWorkflowRestartDispatchInTransaction, V as consumeWorkflowRestartInTransaction, P as readWorkflowRestartCommandInTransaction, N as readWorkflowRestartObservationInTransaction, I as readWorkflowRestartReservationInTransaction, L as reserveWorkflowRestartInTransaction, B as resetReservedWorkflowJournal, F as withdrawWorkflowRestartInTransaction, x as workflowRestartRequestsTable, E as workflowRestartWithdrawalsTable };
|
|
@@ -1,29 +1,30 @@
|
|
|
1
1
|
import { beginWorkflowControlDispatchInTransaction as e, bindWorkflowResumeJournalInTransaction as t } from "./controlRequest.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
2
|
+
import { JournalRoutingGuard as n, ownedJournalRoutingPromise as r, protectJournalRoutingEffect as i } from "./journalRoutingGuard.js";
|
|
3
|
+
import { observeWorkflowSuspension as a, resetExpectedWorkflowSuspension as o } from "./workflowJournalReset.js";
|
|
4
|
+
import { Context as s, Effect as c, Option as l } from "effect";
|
|
5
|
+
import { SqlClient as u } from "effect/sql";
|
|
6
|
+
import { Sharding as d } from "effect/cluster";
|
|
6
7
|
//#region src/workflowResumeDispatch.ts
|
|
7
|
-
var
|
|
8
|
-
let
|
|
9
|
-
if (
|
|
10
|
-
let l = yield*
|
|
8
|
+
var f = (n) => c.gen(function* () {
|
|
9
|
+
let i = yield* c.context(), s = yield* r(() => n.transaction((e) => t(e, n.requestId, (e) => c.runPromiseWith(i)(a(e)))));
|
|
10
|
+
if (s.kind !== "bound") return s;
|
|
11
|
+
let l = yield* r(() => n.transaction((t) => e(t, n.requestId)));
|
|
11
12
|
if (l.kind !== "dispatch") return l;
|
|
12
13
|
let { request: u } = l;
|
|
13
|
-
if (u.operation !== "resume" || u.resumeJournal === null) return yield*
|
|
14
|
-
let
|
|
14
|
+
if (u.operation !== "resume" || u.resumeJournal === null) return yield* c.die(/* @__PURE__ */ Error("Resume dispatch requires its committed suspension binding"));
|
|
15
|
+
let f = yield* o({
|
|
15
16
|
workflowName: u.workflowName,
|
|
16
17
|
executionId: u.executionId,
|
|
17
18
|
...u.resumeJournal
|
|
18
19
|
});
|
|
19
|
-
return yield* (yield*
|
|
20
|
+
return yield* (yield* d.Sharding).pollStorage, {
|
|
20
21
|
kind: "attempted",
|
|
21
22
|
request: u,
|
|
22
|
-
journal:
|
|
23
|
+
journal: f
|
|
23
24
|
};
|
|
24
|
-
}),
|
|
25
|
-
let e = yield*
|
|
26
|
-
return
|
|
25
|
+
}), p = class extends s.Service()("@voltro/workflow/WorkflowResumeDispatcher") {}, m = c.gen(function* () {
|
|
26
|
+
let e = l.getOrUndefined(yield* c.serviceOption(n)), t = yield* u.SqlClient, r = yield* d.Sharding;
|
|
27
|
+
return p.of({ dispatch: (n) => i(e, f(n)).pipe(c.provideService(u.SqlClient, t), c.provideService(d.Sharding, r)) });
|
|
27
28
|
});
|
|
28
29
|
//#endregion
|
|
29
|
-
export {
|
|
30
|
+
export { p as WorkflowResumeDispatcher, f as dispatchWorkflowResume, m as makeWorkflowResumeDispatcher };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { JournalRoutingGuard as e } from "./journalRoutingGuard.js";
|
|
2
|
+
import { Context as t, Effect as n, Option as r } from "effect";
|
|
3
|
+
import { Sharding as i } from "effect/cluster";
|
|
4
|
+
//#region src/workflowRuntimeReadiness.ts
|
|
5
|
+
var a = class extends t.Service()("@voltro/workflow/WorkflowRuntimeReadiness") {}, o = n.gen(function* () {
|
|
6
|
+
let t = yield* i.Sharding, a = r.getOrUndefined(yield* n.serviceOption(e)), o = !0;
|
|
7
|
+
return yield* n.addFinalizer(() => n.sync(() => {
|
|
8
|
+
o = !1;
|
|
9
|
+
})), { isReady: () => o && !a?.isClosed() && !n.runSync(t.isShutdown) };
|
|
10
|
+
}), s = n.map(n.serviceOption(a), (e) => r.isSome(e) ? e.value.isReady : () => !0);
|
|
11
|
+
//#endregion
|
|
12
|
+
export { a as WorkflowRuntimeReadiness, s as captureWorkflowRuntimeReadiness, o as makeWorkflowRuntimeReadiness };
|