@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.
Files changed (103) hide show
  1. package/CHANGELOG.md +5987 -0
  2. package/THIRD-PARTY-NOTICES.md +1122 -31
  3. package/dist/admission.js +140 -0
  4. package/dist/admissionDrainer.js +705 -0
  5. package/dist/admissionGate.js +115 -0
  6. package/dist/admissionStore.js +347 -0
  7. package/dist/admissionSubmission.js +297 -0
  8. package/dist/admissionTables.js +137 -0
  9. package/dist/admissionTransaction.js +21 -0
  10. package/dist/awaitEvent.js +82 -0
  11. package/dist/budgetHold.js +136 -0
  12. package/dist/cancelOnPlan.js +75 -0
  13. package/dist/cancelOnSweep.js +188 -0
  14. package/dist/cancelPendingStart.js +50 -0
  15. package/dist/cluster.d.ts +111 -27
  16. package/dist/cluster.js +12 -2
  17. package/dist/clusterCron.js +19 -0
  18. package/dist/clusterDiagnostics.js +20 -0
  19. package/dist/clusterDiagnosticsSql.js +145 -0
  20. package/dist/clusterLayer.js +145 -0
  21. package/dist/clusterMigrationGate.js +61 -0
  22. package/dist/clusterRunnerLayer.js +31 -0
  23. package/dist/clusterShardGroups.js +33 -0
  24. package/dist/clusterTestSuite.d.ts +23 -0
  25. package/dist/clusterTestSuite.js +209 -179
  26. package/dist/controlMonitor.js +13 -0
  27. package/dist/controlRequest.js +367 -0
  28. package/dist/executionRefusal.js +162 -0
  29. package/dist/failureHandoff.js +183 -0
  30. package/dist/failureMessage.js +12 -0
  31. package/dist/failureRecovery.js +50 -0
  32. package/dist/failureReportStore.js +60 -0
  33. package/dist/flowControl.js +142 -0
  34. package/dist/forwardStartReceipts.js +41 -0
  35. package/dist/inMemoryLayer.js +7 -0
  36. package/dist/inMemoryRecorder.js +56 -0
  37. package/dist/index.d.ts +129 -30
  38. package/dist/index.js +50 -5
  39. package/dist/inspectWorkflow.js +101 -0
  40. package/dist/{journalEncryption-DTyhUzaS.js → journalEncryption.js} +30 -37
  41. package/dist/journalRoutingGuard.js +50 -0
  42. package/dist/journalRoutingLayout.js +47 -0
  43. package/dist/journalRoutingLock.js +39 -0
  44. package/dist/journalRoutingMaintenance.js +24 -0
  45. package/dist/journalRoutingMessageStorage.js +32 -0
  46. package/dist/journalRoutingNamespace.js +23 -0
  47. package/dist/journalRoutingRuntime.js +33 -0
  48. package/dist/journalRoutingSharding.js +28 -0
  49. package/dist/journalRoutingState.js +93 -0
  50. package/dist/journalRoutingTable.js +11 -0
  51. package/dist/journalRoutingTransaction.js +16 -0
  52. package/dist/messages.js +92 -0
  53. package/dist/nondeterminism.js +51 -0
  54. package/dist/parentClosure.js +141 -0
  55. package/dist/parentClosureRecovery.js +54 -0
  56. package/dist/pendingSubmission.js +85 -0
  57. package/dist/prepareSubmissionDispatch.js +17 -0
  58. package/dist/preparedExecution.js +14 -0
  59. package/dist/primitives.js +225 -2
  60. package/dist/queuedCancellationRequest.js +364 -0
  61. package/dist/queuedControl.js +21 -0
  62. package/dist/recorder.js +11 -0
  63. package/dist/residentExecutionEvidence.js +64 -0
  64. package/dist/retryPolicy.js +57 -0
  65. package/dist/runEventsTable.js +17 -0
  66. package/dist/runGeneration.js +345 -0
  67. package/dist/runRecording.js +615 -0
  68. package/dist/runStepsTable.js +28 -0
  69. package/dist/runnerStorageGuard.js +29 -0
  70. package/dist/runsTable.js +42 -0
  71. package/dist/scheduleDeclaration.js +44 -0
  72. package/dist/signalHint.js +23 -0
  73. package/dist/signals.js +70 -0
  74. package/dist/signalsSuspending.js +57 -0
  75. package/dist/sqliteWorkflowOwnership.js +26 -0
  76. package/dist/stalenessSweep.js +191 -0
  77. package/dist/startContextsTable.js +20 -0
  78. package/dist/startReceipt.js +143 -0
  79. package/dist/submissionRecovery.js +122 -0
  80. package/dist/submissionRejection.js +10 -0
  81. package/dist/submissionRetry.js +71 -0
  82. package/dist/suspensionUnavailable.js +9 -0
  83. package/dist/updates.js +87 -0
  84. package/dist/watermarkTable.js +9 -0
  85. package/dist/webCrypto.js +17 -0
  86. package/dist/workflowDelivery.js +24 -0
  87. package/dist/workflowExecutorRouting.js +33 -0
  88. package/dist/workflowJournal.js +124 -0
  89. package/dist/workflowJournalReset.js +111 -0
  90. package/dist/workflowReadSelections.js +12 -0
  91. package/dist/workflowRestartDispatch.js +35 -0
  92. package/dist/workflowRestartObservation.js +60 -0
  93. package/dist/workflowRestartPreparation.js +109 -0
  94. package/dist/workflowRestartReservation.js +427 -0
  95. package/dist/workflowResumeDispatch.js +30 -0
  96. package/dist/workflowRuntimeReadiness.js +12 -0
  97. package/dist/workflowShardRelocation.js +58 -0
  98. package/dist/workflowShardRelocationSql.js +72 -0
  99. package/package.json +4 -4
  100. package/dist/cluster-F_bhqVP7.js +0 -679
  101. package/dist/primitives-DX04WTWh.js +0 -507
  102. package/dist/src-C2NEyUM8.js +0 -3925
  103. package/dist/workflowReadSelections-CZAUjP7f.js +0 -2096
@@ -0,0 +1,60 @@
1
+ import "./workflowDelivery.js";
2
+ import { activityPrimaryKey as e, classifyRunReply as t, runEntityAddress as n } from "./workflowJournal.js";
3
+ import { Effect as r, Option as i, Schema as a } from "effect";
4
+ import { SqlClient as o } from "effect/sql";
5
+ import { MessageStorage as s, Sharding as c } from "effect/cluster";
6
+ //#region src/workflowRestartObservation.ts
7
+ var l = a.fromJsonString(a.Record(a.String, a.String)), u = (u) => r.gen(function* () {
8
+ if (!/^[1-9]\d*$/.test(u.delivery.requestId) || u.executionId.length === 0 || u.activities.some((e) => e.name.length === 0 || !Number.isSafeInteger(e.attempt) || e.attempt < 1)) return yield* r.die(/* @__PURE__ */ Error("Restart observation requires an exact delivery and valid activity attempts"));
9
+ let d = (yield* o.SqlClient).withoutTransforms(), f = yield* s.MessageStorage, p = yield* c.Sharding, m = n(u.workflow, u.executionId, p), h = (e, t) => r.gen(function* () {
10
+ let [n] = yield* d`SELECT m.entity_type, m.entity_id, m.tag, m.headers, r.id AS reply_id, r.payload
11
+ FROM cluster_messages m
12
+ LEFT JOIN cluster_replies r ON r.id = m.last_reply_id AND r.request_id = m.id AND r.kind = 0
13
+ WHERE m.id = ${e} AND m.kind = 0`;
14
+ if (n !== void 0) return n.entity_type !== `Workflow/${u.workflow._tag}` || n.entity_id !== u.executionId || n.tag !== t ? yield* r.die(/* @__PURE__ */ Error("Restart observation belongs to another execution or procedure")) : n;
15
+ }), g = yield* h(u.delivery.requestId, "run");
16
+ if (g === void 0) return {
17
+ kind: "unavailable",
18
+ reason: "no-journal"
19
+ };
20
+ if (((yield* r.sync(() => a.decodeUnknownSync(l)(g.headers)))["voltro-workflow-restart"] ?? null) !== u.delivery.restartToken) return {
21
+ kind: "unavailable",
22
+ reason: "delivery-changed"
23
+ };
24
+ if (g.reply_id === null || g.payload === null) return {
25
+ kind: "unavailable",
26
+ reason: "no-reply"
27
+ };
28
+ let _ = t(yield* r.sync(() => JSON.parse(g.payload)));
29
+ if (_ !== "failed") return {
30
+ kind: "unavailable",
31
+ reason: _
32
+ };
33
+ let v = /* @__PURE__ */ new Map([[u.delivery.requestId, String(g.reply_id)]]);
34
+ for (let t of u.activities) {
35
+ let n = yield* f.requestIdForPrimaryKey({
36
+ address: m,
37
+ tag: "activity",
38
+ id: e(t.name, t.attempt)
39
+ });
40
+ if (i.isNone(n)) return {
41
+ kind: "unavailable",
42
+ reason: "activity-not-found"
43
+ };
44
+ let r = String(n.value), a = yield* h(r, "activity");
45
+ if (a?.reply_id == null) return {
46
+ kind: "unavailable",
47
+ reason: "activity-not-found"
48
+ };
49
+ v.set(r, String(a.reply_id));
50
+ }
51
+ return {
52
+ kind: "observed",
53
+ replies: [...v].map(([e, t]) => ({
54
+ requestId: e,
55
+ replyId: t
56
+ }))
57
+ };
58
+ }).pipe(r.provideService(o.SafeIntegers, !0));
59
+ //#endregion
60
+ export { u as observeWorkflowRestartReplies };
@@ -0,0 +1,109 @@
1
+ import { readWorkflowRestartCommandInTransaction as e, readWorkflowRestartReservationInTransaction as t, reserveWorkflowRestartInTransaction as n } from "./workflowRestartReservation.js";
2
+ import { Schema as r } from "effect";
3
+ import { eq as i } from "@voltro/database";
4
+ //#region src/workflowRestartPreparation.ts
5
+ var a = async (t) => {
6
+ if (t.workflow._tag !== t.command.workflowName || t.control.workflowName !== t.command.workflowName) throw Error("Restart preparation requires the matching workflow");
7
+ let n = await t.transaction(async (n) => {
8
+ let a = await e(n, t.command);
9
+ if (a !== void 0) return {
10
+ kind: "accepted",
11
+ request: a
12
+ };
13
+ let [o] = await n.query({
14
+ table: "_voltro_workflow_runs",
15
+ predicate: i("id", t.command.runId),
16
+ lock: "update",
17
+ order: [],
18
+ take: 1,
19
+ skip: void 0,
20
+ projection: ["runnerGeneration"]
21
+ });
22
+ return {
23
+ kind: "captured",
24
+ generation: r.decodeUnknownSync(r.NonEmptyString)(o?.runnerGeneration)
25
+ };
26
+ });
27
+ return n.kind === "accepted" ? {
28
+ kind: "reserved",
29
+ request: n.request,
30
+ reused: !0
31
+ } : s({
32
+ ...t,
33
+ command: {
34
+ ...t.command,
35
+ generation: n.generation
36
+ }
37
+ });
38
+ }, o = r.Struct({
39
+ requestId: r.NonEmptyString,
40
+ restartToken: r.NullOr(r.NonEmptyString)
41
+ }), s = async (e) => {
42
+ let { command: a } = e;
43
+ if (e.workflow._tag !== a.workflowName || e.control.workflowName !== a.workflowName) throw Error("Restart preparation requires the matching workflow");
44
+ let s = await e.transaction(async (n) => {
45
+ let s = await t(n, a);
46
+ if (s !== void 0) return {
47
+ kind: "accepted",
48
+ request: s
49
+ };
50
+ let [c] = await n.query({
51
+ table: "_voltro_workflow_runs",
52
+ predicate: i("id", a.runId),
53
+ lock: "update",
54
+ order: [],
55
+ take: 1,
56
+ skip: void 0,
57
+ projection: void 0
58
+ });
59
+ if (c === void 0 || c.tag !== a.workflowName || c.runnerGeneration !== a.generation || c.status !== "failed" || c.discardedAt != null || typeof c.executionId != "string" || c.executionId.length === 0) throw Error("Restart preparation requires its failed resident generation");
60
+ if ((r.decodeUnknownSync(r.NullOr(r.Struct({ tenantId: r.NullOr(r.NonEmptyString) })))(c.subject ?? null)?.tenantId ?? null) !== a.tenantId) throw Error("Restart preparation belongs to another tenant");
61
+ return {
62
+ kind: "observe",
63
+ executionId: c.executionId,
64
+ delivery: r.decodeUnknownSync(o)(c.engineDelivery),
65
+ activities: await e.readActivities(n)
66
+ };
67
+ });
68
+ if (s.kind === "accepted") return {
69
+ kind: "reserved",
70
+ request: s.request,
71
+ reused: !0
72
+ };
73
+ let c = await e.observe({
74
+ workflow: e.workflow,
75
+ executionId: s.executionId,
76
+ delivery: s.delivery,
77
+ activities: s.activities
78
+ });
79
+ return e.transaction(async (r) => {
80
+ let o = await t(r, a);
81
+ if (o !== void 0) return {
82
+ kind: "reserved",
83
+ request: o,
84
+ reused: !0
85
+ };
86
+ if (c.kind === "unavailable") return c;
87
+ let [l] = await r.query({
88
+ table: "_voltro_workflow_runs",
89
+ predicate: i("id", a.runId),
90
+ lock: "update",
91
+ order: [],
92
+ take: 1,
93
+ skip: void 0,
94
+ projection: ["executionId"]
95
+ });
96
+ if (l?.executionId !== s.executionId) throw Error("Restart execution changed during observation");
97
+ return n(r, {
98
+ ...a,
99
+ token: e.createToken(),
100
+ delivery: s.delivery,
101
+ replies: c.replies,
102
+ control: e.control,
103
+ paused: await e.readPaused(r),
104
+ now: e.now
105
+ });
106
+ });
107
+ };
108
+ //#endregion
109
+ export { s as prepareWorkflowRestart, a as prepareWorkflowRestartCommand };
@@ -0,0 +1,427 @@
1
+ import { resolveAdmissionKeys as e } from "./admission.js";
2
+ import { decodePendingPayload as t, evaluateAdmission as n, recordAdmission as r } from "./admissionStore.js";
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";
8
+ //#region src/workflowRestartReservation.ts
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),
49
+ lock: "update",
50
+ order: [],
51
+ take: 1,
52
+ skip: void 0,
53
+ projection: void 0
54
+ });
55
+ if (r === void 0) return;
56
+ let i = s.decodeUnknownSync(D)(r);
57
+ if (i.runId !== n.runId) throw Error("Restart identity belongs to a different command");
58
+ if (!Number.isFinite(i.withdrawnAt.getTime())) throw Error("Invalid restart withdrawal timestamp");
59
+ return i;
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
77
+ })),
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),
85
+ lock: "update",
86
+ order: [],
87
+ take: 1,
88
+ skip: void 0,
89
+ projection: void 0
90
+ });
91
+ if (r === void 0) return;
92
+ let i = s.decodeUnknownSync(A)(r);
93
+ if (i.runId !== n.runId) throw Error("Restart identity belongs to a different command");
94
+ return i;
95
+ }, N = async (e, t) => {
96
+ let n = await O(e, t);
97
+ if (n !== void 0) return s.decodeUnknownSync(c)({
98
+ ...t,
99
+ kind: "withdrawn",
100
+ workflowName: n.workflowName,
101
+ selection: n.selection,
102
+ withdrawnAt: n.withdrawnAt.getTime()
103
+ });
104
+ let r = await M(e, t);
105
+ if (r === void 0) return s.decodeUnknownSync(c)({
106
+ ...t,
107
+ kind: "not-found"
108
+ });
109
+ let i = {
110
+ requestId: r.id,
111
+ runId: r.runId,
112
+ workflowName: r.workflowName,
113
+ executionId: r.executionId,
114
+ originalGeneration: r.generation,
115
+ selection: r.selection,
116
+ requestedAt: r.requestedAt.getTime(),
117
+ dispatchAttempts: r.dispatchAttempts
118
+ };
119
+ return s.decodeUnknownSync(c)(r.enteredGeneration === null ? {
120
+ ...i,
121
+ kind: "pending"
122
+ } : {
123
+ ...i,
124
+ kind: "entered",
125
+ enteredGeneration: r.enteredGeneration
126
+ });
127
+ }, P = async (e, t) => {
128
+ for (let e of [
129
+ t.id,
130
+ t.runId,
131
+ t.workflowName
132
+ ]) s.decodeUnknownSync(S)(e);
133
+ if (t.id.length > 64) throw Error("Invalid restart request identity");
134
+ s.decodeUnknownSync(s.NullOr(S))(t.tenantId);
135
+ let n = s.decodeUnknownSync(T)(t.selection);
136
+ await k(e, {
137
+ requestId: t.id,
138
+ runId: t.runId
139
+ });
140
+ let r = await M(e, {
141
+ requestId: t.id,
142
+ runId: t.runId
143
+ });
144
+ if (r !== void 0) {
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");
146
+ return r;
147
+ }
148
+ }, F = async (e, t) => {
149
+ let n = s.decodeUnknownSync(D)({
150
+ ...t,
151
+ withdrawnAt: new Date(t.now)
152
+ });
153
+ if (s.decodeUnknownSync(u)({
154
+ requestId: n.id,
155
+ runId: n.runId
156
+ }), !Number.isFinite(n.withdrawnAt.getTime())) throw Error("Invalid restart withdrawal timestamp");
157
+ let r = await O(e, {
158
+ requestId: n.id,
159
+ runId: n.runId
160
+ });
161
+ if (r !== void 0) {
162
+ if (r.workflowName !== n.workflowName || r.tenantId !== n.tenantId || !j(r.selection, n.selection)) throw Error("Restart identity belongs to a different command");
163
+ return {
164
+ kind: "withdrawn",
165
+ withdrawal: r,
166
+ reused: !0
167
+ };
168
+ }
169
+ let i = await P(e, n);
170
+ if (i !== void 0) return {
171
+ kind: "reserved",
172
+ request: i
173
+ };
174
+ let [a] = await e.query({
175
+ table: "_voltro_workflow_runs",
176
+ predicate: p("id", n.runId),
177
+ lock: "update",
178
+ order: [],
179
+ take: 1,
180
+ skip: void 0,
181
+ projection: void 0
182
+ });
183
+ if (a === void 0 || a.tag !== n.workflowName) throw Error("Restart withdrawal requires its resident workflow");
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), {
186
+ kind: "withdrawn",
187
+ withdrawal: n,
188
+ reused: !1
189
+ };
190
+ }, I = async (e, t) => {
191
+ s.decodeUnknownSync(S)(t.generation);
192
+ let n = await P(e, t);
193
+ if (n !== void 0 && n.generation !== t.generation) throw Error("Restart identity belongs to a different command");
194
+ return n;
195
+ }, L = async (i, a) => {
196
+ for (let e of [
197
+ a.id,
198
+ a.runId,
199
+ a.generation,
200
+ a.token
201
+ ]) s.decodeUnknownSync(S)(e);
202
+ if (a.id.length > 64 || !Number.isFinite(new Date(a.now).getTime())) throw Error("Invalid restart request identity or timestamp");
203
+ await k(i, {
204
+ requestId: a.id,
205
+ runId: a.runId
206
+ });
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();
210
+ for (let e of l) {
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);
213
+ }
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),
218
+ lock: "update",
219
+ order: [],
220
+ take: 1,
221
+ skip: void 0,
222
+ projection: void 0
223
+ });
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");
227
+ return {
228
+ kind: "reserved",
229
+ request: e,
230
+ reused: !0
231
+ };
232
+ }
233
+ let [m] = await i.query({
234
+ table: "_voltro_workflow_runs",
235
+ predicate: p("id", a.runId),
236
+ lock: "update",
237
+ order: [],
238
+ take: 1,
239
+ skip: void 0,
240
+ projection: void 0
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");
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))),
249
+ lock: "update",
250
+ order: [],
251
+ take: 1,
252
+ skip: void 0,
253
+ projection: ["id", "generation"]
254
+ });
255
+ if (g !== void 0) {
256
+ if (g.generation !== a.generation) throw Error("Restart delivery token was already used by this run");
257
+ return { kind: "already-requested" };
258
+ }
259
+ let v = t(i, a.control.workflowName, m.payload), y = e(a.control, v), b = await n({
260
+ store: i,
261
+ control: a.control,
262
+ keys: y,
263
+ paused: a.paused,
264
+ now: a.now,
265
+ reconsidering: !0
266
+ });
267
+ if (b.kind !== "admit") return {
268
+ kind: "not-admitted",
269
+ decision: b
270
+ };
271
+ let E = await r({
272
+ store: i,
273
+ control: a.control,
274
+ keys: y,
275
+ outcome: "admitted",
276
+ mode: "restart",
277
+ reason: b.reason,
278
+ collapsed: 1,
279
+ waitedMs: 0,
280
+ executionId: null,
281
+ runId: null,
282
+ tenantId: a.tenantId,
283
+ now: a.now
284
+ });
285
+ if (E === void 0) throw Error("Restart has no admission reservation");
286
+ let D = s.decodeUnknownSync(A)({
287
+ id: a.id,
288
+ runId: a.runId,
289
+ workflowName: a.control.workflowName,
290
+ executionId: m.executionId,
291
+ generation: a.generation,
292
+ token: a.token,
293
+ ledgerId: E,
294
+ tenantId: a.tenantId,
295
+ delivery: o,
296
+ replies: l,
297
+ selection: c,
298
+ eviction: b.evict ?? null,
299
+ requestedAt: new Date(a.now),
300
+ dispatchAttempts: 0,
301
+ enteredGeneration: null
302
+ });
303
+ return await i.insert(x.tableName, D), {
304
+ kind: "reserved",
305
+ request: D,
306
+ reused: !1
307
+ };
308
+ }, R = async (e, t) => {
309
+ let [n] = await e.query({
310
+ table: x.tableName,
311
+ predicate: p("id", t),
312
+ lock: "update",
313
+ order: [],
314
+ take: 1,
315
+ skip: void 0,
316
+ projection: void 0
317
+ });
318
+ if (n === void 0) throw Error("Restart dispatch has no resident request");
319
+ let r = s.decodeUnknownSync(A)(n);
320
+ if (r.enteredGeneration !== null) throw Error("Restart request has already entered its resident generation");
321
+ let [i] = await e.query({
322
+ table: "_voltro_workflow_admissions",
323
+ predicate: p("id", r.ledgerId),
324
+ lock: "update",
325
+ order: [],
326
+ take: 1,
327
+ skip: void 0,
328
+ projection: void 0
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");
331
+ let [a] = await e.query({
332
+ table: "_voltro_workflow_runs",
333
+ predicate: p("id", r.runId),
334
+ lock: "update",
335
+ order: [],
336
+ take: 1,
337
+ skip: void 0,
338
+ projection: void 0
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");
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");
343
+ return {
344
+ request: r,
345
+ run: a
346
+ };
347
+ }, z = async (e, t) => {
348
+ let { request: n } = await R(e, t), r = n.dispatchAttempts + 1;
349
+ if (!Number.isSafeInteger(r)) throw Error("Restart dispatch attempt counter exhausted");
350
+ if (await e.update(x.tableName, t, { dispatchAttempts: r }) === null) throw Error("Restart request disappeared before dispatch");
351
+ return {
352
+ ...n,
353
+ dispatchAttempts: r
354
+ };
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, {
360
+ requestId: n.delivery.requestId,
361
+ previousToken: n.delivery.restartToken,
362
+ token: n.token,
363
+ workflowName: n.workflowName,
364
+ executionId: n.executionId
365
+ });
366
+ }), V = async (e, t) => {
367
+ for (let e of [
368
+ t.runId,
369
+ t.workflowName,
370
+ t.executionId,
371
+ t.generation
372
+ ]) s.decodeUnknownSync(S)(e);
373
+ if (!Number.isFinite(new Date(t.now).getTime())) throw Error("Restart entry requires a valid timestamp");
374
+ let n = s.decodeUnknownSync(C)(t.delivery);
375
+ if (n.restartToken === null) throw Error("Restart entry has no delivery token");
376
+ let [r] = await e.query({
377
+ table: x.tableName,
378
+ predicate: d(p("runId", t.runId), p("token", n.restartToken)),
379
+ lock: "update",
380
+ order: [],
381
+ take: 1,
382
+ skip: void 0,
383
+ projection: ["id"]
384
+ });
385
+ if (r === void 0) throw Error("Restart delivery has no matching resident request");
386
+ let { request: i, run: a } = await R(e, s.decodeUnknownSync(S)(r.id));
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");
388
+ if (i.dispatchAttempts === 0) throw Error("Restart entry has no committed dispatch attempt");
389
+ if (await e.update("_voltro_workflow_admissions", i.ledgerId, {
390
+ executionId: i.executionId,
391
+ runId: i.runId
392
+ }) === null) throw Error("Restart reservation disappeared during entry");
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, {
395
+ runnerGeneration: t.generation,
396
+ engineDelivery: n,
397
+ runnerEnteredAt: new Date(t.now),
398
+ reclaimCount: 0,
399
+ status: "running",
400
+ errorTag: null,
401
+ errorMessage: null,
402
+ output: null,
403
+ completedAt: null,
404
+ durationMs: null
405
+ });
406
+ if (o === null) throw Error("Restart run disappeared during entry");
407
+ return {
408
+ row: o,
409
+ previous: a,
410
+ event: await e.insert("_voltro_workflow_run_events", {
411
+ id: f("wfev", JSON.stringify(["restart", i.id])),
412
+ runId: i.runId,
413
+ eventType: "run-redriven",
414
+ occurredAt: new Date(t.now),
415
+ stepName: null,
416
+ attempt: null,
417
+ payload: {
418
+ requestId: i.id,
419
+ executionId: i.executionId,
420
+ previousGeneration: i.generation,
421
+ generation: t.generation
422
+ }
423
+ })
424
+ };
425
+ };
426
+ //#endregion
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 };
@@ -0,0 +1,30 @@
1
+ import { beginWorkflowControlDispatchInTransaction as e, bindWorkflowResumeJournalInTransaction as t } from "./controlRequest.js";
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";
7
+ //#region src/workflowResumeDispatch.ts
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)));
12
+ if (l.kind !== "dispatch") return l;
13
+ let { request: u } = l;
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({
16
+ workflowName: u.workflowName,
17
+ executionId: u.executionId,
18
+ ...u.resumeJournal
19
+ });
20
+ return yield* (yield* d.Sharding).pollStorage, {
21
+ kind: "attempted",
22
+ request: u,
23
+ journal: f
24
+ };
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)) });
28
+ });
29
+ //#endregion
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 };