@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
|
@@ -1,17 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
if (typeof t == "string" && t.length > 0) return t;
|
|
7
|
-
if (typeof e == "object" && e && typeof e.toJSON == "function") {
|
|
8
|
-
let { _tag: t, ...n } = e.toJSON(), r = typeof t == "string" ? t : String(e);
|
|
9
|
-
return Object.keys(n).length === 0 ? r : `${r}: ${JSON.stringify(n)}`;
|
|
10
|
-
}
|
|
11
|
-
return String(e);
|
|
12
|
-
}, u = () => void 0, d = (e) => {
|
|
1
|
+
import { failureMessage as e } from "./failureMessage.js";
|
|
2
|
+
import { Activity as t } from "effect/workflow";
|
|
3
|
+
import { Cause as n, Context as r, Effect as i, Effectable as a, Schema as o, SchemaAST as s, SchemaGetter as c, SchemaIssue as l } from "effect";
|
|
4
|
+
//#region src/journalEncryption.ts
|
|
5
|
+
var u = () => void 0, d = (e) => {
|
|
13
6
|
u = typeof e == "function" ? e : () => e;
|
|
14
|
-
}, f = () => u(), p =
|
|
7
|
+
}, f = () => u(), p = r.Reference("@voltro/workflow/CurrentWorkflowEncrypted", { defaultValue: () => !1 }), m = { column: "workflow-journal" }, h = /* @__PURE__ */ new Set(), g = (e) => {
|
|
15
8
|
h.add(e);
|
|
16
9
|
}, _ = /* @__PURE__ */ new Set(), v = (e) => {
|
|
17
10
|
_.add(e);
|
|
@@ -25,21 +18,21 @@ var l = (e) => {
|
|
|
25
18
|
let r = u();
|
|
26
19
|
if (r === void 0) throw S(t);
|
|
27
20
|
return JSON.parse(r.decrypt(e, n));
|
|
28
|
-
}, T = (e) =>
|
|
21
|
+
}, T = (e) => s.isVoid(e) || s.isNever(e) || s.isUndefined(e), E = (e, t) => {
|
|
29
22
|
if (T(e.ast)) return e;
|
|
30
23
|
let n = (e, t) => {
|
|
31
24
|
try {
|
|
32
|
-
return
|
|
25
|
+
return i.succeed(t());
|
|
33
26
|
} catch (t) {
|
|
34
|
-
return
|
|
27
|
+
return i.fail(new l.InvalidValue({ message: t.message }, e));
|
|
35
28
|
}
|
|
36
29
|
};
|
|
37
|
-
return (e.ast.context?.isOptional === !0 ?
|
|
38
|
-
decode:
|
|
39
|
-
encode:
|
|
30
|
+
return (e.ast.context?.isOptional === !0 ? o.optionalKey(o.Unknown) : o.Unknown).pipe(o.decodeTo(e, {
|
|
31
|
+
decode: c.transformEffect((e) => n(e, () => Array.isArray(e) ? e.map((e) => w(e, t)) : w(e, t))),
|
|
32
|
+
encode: c.transformEffect((e) => n(e, () => e === void 0 ? void 0 : C(e, t)))
|
|
40
33
|
}));
|
|
41
34
|
}, D = (e, t) => {
|
|
42
|
-
let n =
|
|
35
|
+
let n = o.isSchema(t) ? t.fields : t, r = `workflow '${e}' payload`, i = {};
|
|
43
36
|
for (let [e, t] of Object.entries(n)) i[e] = E(t, `${r}.${e}`);
|
|
44
37
|
return i;
|
|
45
38
|
}, O = (e) => typeof e == "object" && !!e && !Array.isArray(e), k = (e, t) => {
|
|
@@ -102,21 +95,21 @@ var l = (e) => {
|
|
|
102
95
|
let t = { ...e };
|
|
103
96
|
for (let e of z) x(t[e]) && (t[e] = L(t[e], `workflow event ${e}`));
|
|
104
97
|
return t;
|
|
105
|
-
}, H = (
|
|
106
|
-
let n =
|
|
107
|
-
...
|
|
108
|
-
error:
|
|
109
|
-
}),
|
|
110
|
-
...
|
|
111
|
-
success: E(
|
|
112
|
-
error:
|
|
113
|
-
execute:
|
|
98
|
+
}, H = (e) => {
|
|
99
|
+
let n = t.make({
|
|
100
|
+
...e,
|
|
101
|
+
error: o.Defect()
|
|
102
|
+
}), r, s = `wait '${e.name}'`, c = () => r ??= t.make({
|
|
103
|
+
...e,
|
|
104
|
+
success: E(e.success, `${s} value`),
|
|
105
|
+
error: o.Defect(),
|
|
106
|
+
execute: e.execute.pipe(i.catchDefect((e) => i.die(M(e, `${s} defect`))))
|
|
114
107
|
}), l = n;
|
|
115
108
|
return {
|
|
116
109
|
...n,
|
|
117
|
-
...
|
|
110
|
+
...a.Prototype({
|
|
118
111
|
label: "Activity",
|
|
119
|
-
evaluate: () =>
|
|
112
|
+
evaluate: () => i.flatMap(p, (e) => e ? c().pipe(i.catchDefect((e) => i.die(N(e, `${s} defect`)))) : l)
|
|
120
113
|
})
|
|
121
114
|
};
|
|
122
115
|
}, U = { column: "_voltro_workflow_run_steps:payload" }, W = (e) => {
|
|
@@ -143,12 +136,12 @@ var l = (e) => {
|
|
|
143
136
|
t.payload = k(t.payload, "workflow run payload");
|
|
144
137
|
} catch {}
|
|
145
138
|
return "output" in t && (t.output = L(t.output, "workflow run result")), typeof t.errorMessage == "string" && (t.errorMessage = R(t.errorMessage)), t;
|
|
146
|
-
}, K = (
|
|
147
|
-
if (
|
|
148
|
-
let
|
|
149
|
-
return
|
|
139
|
+
}, K = (t, r) => {
|
|
140
|
+
if (t === void 0 || !b(t)) {
|
|
141
|
+
let t = n.isCause(r) ? n.squash(r) : r;
|
|
142
|
+
return t instanceof Error && t.message.length > 0 ? `${t.name}: ${t.message}` : e(t);
|
|
150
143
|
}
|
|
151
|
-
return `${
|
|
144
|
+
return `${r instanceof Error ? r.name : typeof r}: [withheld — workflow '${t}' is declared encrypted; the full cause is recorded sealed on its row]`;
|
|
152
145
|
};
|
|
153
146
|
//#endregion
|
|
154
|
-
export {
|
|
147
|
+
export { p as CurrentWorkflowEncrypted, j as SEALED_DEFECT_NAME, U as STEP_JOURNAL_BINDING, m as WORKFLOW_JOURNAL_BINDING, F as anyWorkflowEncrypted, H as encryptionAwareActivity, f as getWorkflowJournalCipher, y as isQueueEncrypted, x as isSealedJournalValue, b as isWorkflowEncrypted, K as loggableCause, v as markQueueEncrypted, g as markWorkflowEncrypted, N as openDefect, R as openErrorText, V as openEventPayload, w as openJournalValue, k as openPayloadFields, G as openWorkflowRow, M as sealDefect, I as sealErrorText, B as sealEventPayload, C as sealJournalValue, A as sealPayloadFields, D as sealedPayloadFields, E as sealedSchema, d as setWorkflowJournalCipher, L as tryOpenJournalValue };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Context as e, Deferred as t, Effect as n, Option as r, Schedule as i, Semaphore as a } from "effect";
|
|
2
|
+
//#region src/journalRoutingGuard.ts
|
|
3
|
+
var o = (e) => n.gen(function* () {
|
|
4
|
+
let r = e.pollMs ?? 1e3, o = e.verify;
|
|
5
|
+
if (!Number.isSafeInteger(r) || r < 1 || r > 3e4) return yield* n.fail(/* @__PURE__ */ Error("Invalid journal routing probe interval"));
|
|
6
|
+
let s = yield* t.make(), c = /* @__PURE__ */ new Set(), l = yield* a.make(1), u = !1, d = (e) => n.gen(function* () {
|
|
7
|
+
u = !0, yield* t.fail(s, Error(e));
|
|
8
|
+
}), f = l.withPermits(1)(n.gen(function* () {
|
|
9
|
+
if (u) return yield* t.await(s);
|
|
10
|
+
let e = yield* n.interruptible(o).pipe(n.timeout(r), n.isSuccess);
|
|
11
|
+
if (u) return yield* t.await(s);
|
|
12
|
+
if (!e) return yield* d("Journal routing lock ownership was lost"), yield* t.await(s);
|
|
13
|
+
})), p = (e) => n.uninterruptibleMask((r) => n.gen(function* () {
|
|
14
|
+
if (u) return yield* t.await(s);
|
|
15
|
+
let i = yield* t.make();
|
|
16
|
+
return c.add(i), yield* r(f.pipe(n.andThen(n.suspend(() => u ? t.await(s) : n.raceFirst(e, n.interruptible(t.await(s))))))).pipe(n.ensuring(n.gen(function* () {
|
|
17
|
+
c.delete(i), yield* t.succeed(i, void 0);
|
|
18
|
+
})));
|
|
19
|
+
})), m = (e) => n.uninterruptibleMask((r) => n.gen(function* () {
|
|
20
|
+
if (u) return yield* t.await(s);
|
|
21
|
+
let i = yield* t.make();
|
|
22
|
+
c.add(i);
|
|
23
|
+
let a = new AbortController(), o = Promise.resolve().then(() => {
|
|
24
|
+
if (u) throw Error("Journal routing admission is closed");
|
|
25
|
+
return e(a.signal);
|
|
26
|
+
});
|
|
27
|
+
return yield* r(n.tryPromise({
|
|
28
|
+
try: () => o,
|
|
29
|
+
catch: (e) => e
|
|
30
|
+
})).pipe(n.ensuring(n.gen(function* () {
|
|
31
|
+
a.abort(), yield* n.promise(() => o.then(() => void 0, () => void 0)), c.delete(i), yield* t.succeed(i, void 0);
|
|
32
|
+
})));
|
|
33
|
+
})), h = n.gen(function* () {
|
|
34
|
+
yield* d("Journal routing admission is closed"), yield* n.forEach([...c], (e) => t.await(e), { discard: !0 });
|
|
35
|
+
});
|
|
36
|
+
return yield* n.addFinalizer(() => h), yield* f.pipe(n.ignore, n.repeat(i.spaced(r)), n.forkScoped), {
|
|
37
|
+
run: p,
|
|
38
|
+
ownPromise: m,
|
|
39
|
+
check: f,
|
|
40
|
+
close: h,
|
|
41
|
+
isClosed: () => u
|
|
42
|
+
};
|
|
43
|
+
}), s = e.Service("@voltro/workflow/JournalRoutingGuard"), c = (e, t) => e === void 0 ? t : n.gen(function* () {
|
|
44
|
+
return yield* yield* e.run(n.exit(t.pipe(n.provideService(s, e)))).pipe(n.orDie);
|
|
45
|
+
}), l = (e) => n.flatMap(n.serviceOption(s), (t) => r.isSome(t) ? t.value.ownPromise(e).pipe(n.orDie) : n.promise(e)), u = (e) => n.flatMap(n.serviceOption(s), (t) => r.isSome(t) ? t.value.ownPromise(e) : n.tryPromise({
|
|
46
|
+
try: e,
|
|
47
|
+
catch: (e) => e
|
|
48
|
+
}));
|
|
49
|
+
//#endregion
|
|
50
|
+
export { s as JournalRoutingGuard, o as makeJournalRoutingGuard, l as ownedJournalRoutingPromise, c as protectJournalRoutingEffect, u as tryOwnedJournalRoutingPromise };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
//#region src/journalRoutingLayout.ts
|
|
2
|
+
var e = (e) => {
|
|
3
|
+
if (e !== "default" && e !== "api-workloads-v1") throw Error("Unknown journal routing layout");
|
|
4
|
+
let t = e === "api-workloads-v1";
|
|
5
|
+
return Object.freeze({
|
|
6
|
+
id: e,
|
|
7
|
+
workflowGroup: "default",
|
|
8
|
+
webhookGroup: t ? "voltro.webhooks" : "default",
|
|
9
|
+
cronGroup: t ? "voltro.schedules" : "default",
|
|
10
|
+
available: Object.freeze(t ? [
|
|
11
|
+
"default",
|
|
12
|
+
"voltro.webhooks",
|
|
13
|
+
"voltro.schedules"
|
|
14
|
+
] : ["default"])
|
|
15
|
+
});
|
|
16
|
+
}, t = (t, n) => {
|
|
17
|
+
let r = e(t), i = e(n), a = [];
|
|
18
|
+
return r.webhookGroup !== i.webhookGroup && a.push({
|
|
19
|
+
entity: "workflow",
|
|
20
|
+
name: "voltro.deliverWebhook",
|
|
21
|
+
from: r.webhookGroup,
|
|
22
|
+
to: i.webhookGroup
|
|
23
|
+
}), r.cronGroup !== i.cronGroup && a.push({
|
|
24
|
+
entity: "cron",
|
|
25
|
+
name: "*",
|
|
26
|
+
from: r.cronGroup,
|
|
27
|
+
to: i.cronGroup
|
|
28
|
+
}), Object.freeze(a.map((e) => Object.freeze(e)));
|
|
29
|
+
}, n = (t, n) => {
|
|
30
|
+
let r = e(t);
|
|
31
|
+
return n === "voltro.deliverWebhook" ? r.webhookGroup : r.workflowGroup;
|
|
32
|
+
}, r = (t, n) => {
|
|
33
|
+
let r = e(t), i = [
|
|
34
|
+
n.workflows,
|
|
35
|
+
n.schedules,
|
|
36
|
+
n.webhooks
|
|
37
|
+
];
|
|
38
|
+
if (i.some((e) => typeof e != "boolean")) throw Error("Explicit executor selection is required");
|
|
39
|
+
if (t === "default" && i.some(Boolean) && !i.every(Boolean)) throw Error("Separate executor roles require the api-workloads-v1 journal routing transition");
|
|
40
|
+
let a = /* @__PURE__ */ new Set();
|
|
41
|
+
return n.workflows && a.add(r.workflowGroup), n.schedules && a.add(r.cronGroup), n.webhooks && a.add(r.webhookGroup), Object.freeze({
|
|
42
|
+
available: r.available,
|
|
43
|
+
assigned: Object.freeze([...a])
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
//#endregion
|
|
47
|
+
export { r as journalExecutorGroups, e as journalRoutingLayout, t as journalRoutingTransitions, n as journalWorkflowGroup };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Effect as e } from "effect";
|
|
2
|
+
import { SqlClient as t } from "effect/sql";
|
|
3
|
+
import { fnv1a64 as n } from "@voltro/database/sql";
|
|
4
|
+
//#region src/journalRoutingLock.ts
|
|
5
|
+
var r = (r) => e.gen(function* () {
|
|
6
|
+
let i = r.namespace, a = r.mode, o = r.timeoutMs ?? 3e4;
|
|
7
|
+
if (!i || i.length > 256 || !["shared", "exclusive"].includes(a) || !Number.isSafeInteger(o) || o < 1 || o > 3e5) return yield* e.fail(/* @__PURE__ */ Error("Invalid journal routing lock options"));
|
|
8
|
+
let s = yield* t.SqlClient, c = s.onDialectOrElse({
|
|
9
|
+
pg: () => "pg",
|
|
10
|
+
mssql: () => "mssql",
|
|
11
|
+
orElse: () => "unsupported"
|
|
12
|
+
});
|
|
13
|
+
if (c === "unsupported") return yield* e.fail(/* @__PURE__ */ Error("Journal routing locks require PostgreSQL or SQL Server"));
|
|
14
|
+
let l = (n("voltro:journal-routing:" + i) & 9223372036854775807n).toString(), u = "voltro-journal-routing-" + l, d = yield* s.reserve, f = a === "shared" ? "_shared" : "", p = c === "pg" ? `SELECT pg_try_advisory_lock${f}(${l}::bigint)` : `DECLARE @res int; EXEC @res = sp_getapplock @Resource = '${u}', @LockMode = '${a === "shared" ? "Shared" : "Exclusive"}', @LockOwner = 'Session', @LockTimeout = 0; SELECT @res`, m = c === "pg" ? `SELECT pg_advisory_unlock${f}(${l}::bigint)` : `DECLARE @res int; EXEC @res = sp_releaseapplock @Resource = '${u}', @LockOwner = 'Session'; SELECT @res`, h = performance.now(), g = e.gen(function* () {
|
|
15
|
+
for (;;) {
|
|
16
|
+
let t = (yield* d.executeValues(p, []))[0]?.[0];
|
|
17
|
+
if (c === "pg" ? t === !0 || t === "t" || t === 1 : typeof t == "number" && t >= 0) return;
|
|
18
|
+
if (c === "mssql" && t !== -1) return yield* e.fail(/* @__PURE__ */ Error("Journal routing application lock failed"));
|
|
19
|
+
let n = o - (performance.now() - h);
|
|
20
|
+
if (n <= 0) return yield* e.fail(/* @__PURE__ */ Error("Journal routing lock acquisition timed out"));
|
|
21
|
+
yield* e.sleep(Math.min(n, 100));
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
yield* e.acquireRelease(g, () => d.executeValues(m, []).pipe(e.flatMap((t) => {
|
|
25
|
+
let n = t[0]?.[0];
|
|
26
|
+
return (c === "pg" ? n === !0 || n === "t" || n === 1 : typeof n == "number" && n >= 0) ? e.void : e.die(/* @__PURE__ */ Error("Journal routing lock was lost before release"));
|
|
27
|
+
}), e.orDie));
|
|
28
|
+
let _ = c === "pg" ? `SELECT EXISTS (SELECT 1 FROM pg_locks WHERE locktype = 'advisory' AND pid = pg_backend_pid() AND granted AND classid = (${l}::bigint >> 32)::oid AND objid = (${l}::bigint & 4294967295)::oid AND objsubid = 1 AND mode = '${a === "shared" ? "ShareLock" : "ExclusiveLock"}')` : `SELECT APPLOCK_MODE('public', '${u}', 'Session')`;
|
|
29
|
+
return {
|
|
30
|
+
connection: d,
|
|
31
|
+
dialect: c,
|
|
32
|
+
verify: d.executeValues(_, []).pipe(e.flatMap((t) => {
|
|
33
|
+
let n = t[0]?.[0];
|
|
34
|
+
return (c === "pg" ? n === !0 || n === "t" || n === 1 : n === (a === "shared" ? "Shared" : "Exclusive")) ? e.void : e.fail(/* @__PURE__ */ Error("Journal routing lock ownership was lost"));
|
|
35
|
+
}))
|
|
36
|
+
};
|
|
37
|
+
});
|
|
38
|
+
//#endregion
|
|
39
|
+
export { r as acquireJournalRoutingLock };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { withJournalRoutingTransaction as e } from "./journalRoutingTransaction.js";
|
|
2
|
+
import { acquireJournalRoutingLock as t } from "./journalRoutingLock.js";
|
|
3
|
+
import { JournalRoutingMaintenance as n } from "./workflowShardRelocationSql.js";
|
|
4
|
+
import { Effect as r, Option as i } from "effect";
|
|
5
|
+
import { SqlClient as a } from "effect/sql";
|
|
6
|
+
//#region src/journalRoutingMaintenance.ts
|
|
7
|
+
var o = (o, s = 3e4) => r.gen(function* () {
|
|
8
|
+
let c = yield* a.SqlClient;
|
|
9
|
+
return c.onDialectOrElse({
|
|
10
|
+
pg: () => !0,
|
|
11
|
+
orElse: () => !1
|
|
12
|
+
}) ? n.of({ exclusive: (n) => r.scoped(r.gen(function* () {
|
|
13
|
+
let a = yield* r.serviceOption(c.transactionService);
|
|
14
|
+
if (i.isSome(a)) return yield* r.fail(/* @__PURE__ */ Error("Journal maintenance cannot enter an ambient transaction"));
|
|
15
|
+
let { connection: l } = yield* t({
|
|
16
|
+
namespace: o,
|
|
17
|
+
mode: "exclusive",
|
|
18
|
+
timeoutMs: s
|
|
19
|
+
});
|
|
20
|
+
return yield* e(c, l, n);
|
|
21
|
+
})).pipe(r.provideService(a.SqlClient, c)) }) : yield* r.fail(/* @__PURE__ */ Error("Pinned journal maintenance currently requires PostgreSQL"));
|
|
22
|
+
});
|
|
23
|
+
//#endregion
|
|
24
|
+
export { o as makePostgresJournalRoutingMaintenance };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { protectJournalRoutingEffect as e } from "./journalRoutingGuard.js";
|
|
2
|
+
import { Effect as t } from "effect";
|
|
3
|
+
import { MessageStorage as n } from "effect/cluster";
|
|
4
|
+
import { PersistenceError as r } from "effect/cluster/ClusterError";
|
|
5
|
+
//#region src/journalRoutingMessageStorage.ts
|
|
6
|
+
var i = (i, a) => {
|
|
7
|
+
let o = (e) => t.gen(function* () {
|
|
8
|
+
return yield* yield* a.run(t.exit(e)).pipe(t.mapError((e) => new r({ cause: e })));
|
|
9
|
+
});
|
|
10
|
+
return n.MessageStorage.of({
|
|
11
|
+
saveRequest: (e) => o(t.suspend(() => i.saveRequest(e))),
|
|
12
|
+
saveEnvelope: (e) => o(t.suspend(() => i.saveEnvelope(e))),
|
|
13
|
+
saveReply: (e) => o(t.suspend(() => i.saveReply(e))),
|
|
14
|
+
clearReplies: (e) => o(t.suspend(() => i.clearReplies(e))),
|
|
15
|
+
repliesFor: (e) => o(t.suspend(() => i.repliesFor(e))),
|
|
16
|
+
repliesForUnfiltered: (e) => o(t.suspend(() => i.repliesForUnfiltered(e))),
|
|
17
|
+
requestIdForPrimaryKey: (e) => o(t.suspend(() => i.requestIdForPrimaryKey(e))),
|
|
18
|
+
unprocessedMessages: (e) => o(t.suspend(() => i.unprocessedMessages(e))),
|
|
19
|
+
unprocessedMessagesById: (e) => o(t.suspend(() => i.unprocessedMessagesById(e))),
|
|
20
|
+
resetShards: (e) => o(t.suspend(() => i.resetShards(e))),
|
|
21
|
+
resetRequests: (e) => o(t.suspend(() => i.resetRequests(e))),
|
|
22
|
+
resetAddresses: (e) => o(t.suspend(() => i.resetAddresses(e))),
|
|
23
|
+
withTransaction: (t) => e(a, i.withTransaction(t)),
|
|
24
|
+
resetAddress: (e) => o(t.suspend(() => i.resetAddress(e))),
|
|
25
|
+
clearAddress: (e) => o(t.suspend(() => i.clearAddress(e))),
|
|
26
|
+
registerReplyHandler: (e) => i.registerReplyHandler(e),
|
|
27
|
+
unregisterReplyHandler: (e) => i.unregisterReplyHandler(e),
|
|
28
|
+
unregisterShardReplyHandlers: (e) => i.unregisterShardReplyHandlers(e)
|
|
29
|
+
});
|
|
30
|
+
};
|
|
31
|
+
//#endregion
|
|
32
|
+
export { i as guardJournalMessageStorage };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { workflowJournalRoutingTable as e } from "./journalRoutingTable.js";
|
|
2
|
+
import { Effect as t } from "effect";
|
|
3
|
+
import { SqlClient as n } from "effect/sql";
|
|
4
|
+
//#region src/journalRoutingNamespace.ts
|
|
5
|
+
var r = t.gen(function* () {
|
|
6
|
+
let r = (yield* n.SqlClient).withoutTransforms();
|
|
7
|
+
if (!r.onDialectOrElse({
|
|
8
|
+
pg: () => !0,
|
|
9
|
+
orElse: () => !1
|
|
10
|
+
})) return yield* t.fail(/* @__PURE__ */ Error("Journal namespace resolution requires PostgreSQL"));
|
|
11
|
+
let i = yield* r`
|
|
12
|
+
SELECT n.nspname AS schema_name, current_schema() AS active_schema, c.relkind AS kind,
|
|
13
|
+
format('%I.%I', n.nspname, ${e.tableName}::text) AS routing_table
|
|
14
|
+
FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
15
|
+
WHERE c.oid = to_regclass('cluster_messages')`, a = i[0];
|
|
16
|
+
return i.length !== 1 || !a || a.kind !== "r" || a.schema_name !== a.active_schema ? yield* t.fail(/* @__PURE__ */ Error("Journal table must exist in the active PostgreSQL schema without search-path fallback")) : Object.freeze({
|
|
17
|
+
namespace: `pg:${a.schema_name}:cluster_messages`,
|
|
18
|
+
schema: a.schema_name,
|
|
19
|
+
routingTable: r.literal(a.routing_table)
|
|
20
|
+
});
|
|
21
|
+
}), i = r.pipe(t.map((e) => e.namespace));
|
|
22
|
+
//#endregion
|
|
23
|
+
export { r as resolvePostgresJournalLocation, i as resolvePostgresJournalNamespace };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { journalRoutingLayout as e, journalWorkflowGroup as t } from "./journalRoutingLayout.js";
|
|
2
|
+
import { Context as n } from "effect";
|
|
3
|
+
import { ClusterSchema as r } from "effect/cluster";
|
|
4
|
+
//#region src/journalRoutingRuntime.ts
|
|
5
|
+
var i = class extends n.Service()("@voltro/workflow/JournalRoutingLayout") {}, a = (e, i) => {
|
|
6
|
+
let a = n.add(e.annotations, r.ShardGroup, () => t(i, e._tag));
|
|
7
|
+
return new Proxy(e, { get(e, t, n) {
|
|
8
|
+
return t === "annotations" ? a : Reflect.get(e, t, n);
|
|
9
|
+
} });
|
|
10
|
+
}, o = (t, n) => (e(n), {
|
|
11
|
+
...t,
|
|
12
|
+
register: (e, r) => t.register(a(e, n), r),
|
|
13
|
+
execute: (e, r) => t.execute(a(e, n), r),
|
|
14
|
+
poll: (e, r) => t.poll(a(e, n), r),
|
|
15
|
+
interrupt: (e, r) => t.interrupt(a(e, n), r),
|
|
16
|
+
resume: (e, r) => t.resume(a(e, n), r),
|
|
17
|
+
scheduleClock: (e, r) => t.scheduleClock(a(e, n), r)
|
|
18
|
+
}), s = (n, i) => {
|
|
19
|
+
let a = e(i), o = (e) => e.startsWith("Workflow/") && !e.startsWith("Workflow/-/") ? t(i, e.slice(9)) : e.startsWith("ClusterCron/") ? a.cronGroup : void 0;
|
|
20
|
+
return {
|
|
21
|
+
...n,
|
|
22
|
+
makeClient: (e) => {
|
|
23
|
+
let t = o(e.type);
|
|
24
|
+
return n.makeClient(t === void 0 ? e : e.annotate(r.ShardGroup, () => t));
|
|
25
|
+
},
|
|
26
|
+
registerEntity: (e, t, i) => {
|
|
27
|
+
let a = o(e.type);
|
|
28
|
+
return n.registerEntity(a === void 0 ? e : e.annotate(r.ShardGroup, () => a), t, i);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
//#endregion
|
|
33
|
+
export { i as JournalRoutingLayout, a as routeJournalWorkflow, s as withJournalEntityRouting, o as withJournalWorkflowRouting };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { protectJournalRoutingEffect as e } from "./journalRoutingGuard.js";
|
|
2
|
+
import { Effect as t, Stream as n } from "effect";
|
|
3
|
+
import { Rpc as r, RpcSchema as i } from "effect/rpc";
|
|
4
|
+
//#region src/journalRoutingSharding.ts
|
|
5
|
+
var a = (a, o) => {
|
|
6
|
+
let s = (i) => {
|
|
7
|
+
if (typeof i == "object" && i && r.isWrapper(i)) return {
|
|
8
|
+
...i,
|
|
9
|
+
value: s(i.value)
|
|
10
|
+
};
|
|
11
|
+
if (t.isEffect(i)) return e(o, i);
|
|
12
|
+
if (n.isStream(i)) {
|
|
13
|
+
let r = i;
|
|
14
|
+
return n.unwrap(t.map(e(o, n.toPull(r)), (r) => n.fromPull(t.succeed(e(o, r)))));
|
|
15
|
+
}
|
|
16
|
+
throw Error("Cluster handler must return an Effect, Stream or RPC wrapper");
|
|
17
|
+
};
|
|
18
|
+
return {
|
|
19
|
+
...a,
|
|
20
|
+
registerEntity: (r, c, l) => e(o, t.suspend(() => a.registerEntity(r, c.pipe(t.map((e) => new Proxy(e, { get(e, a, c) {
|
|
21
|
+
let l = Reflect.get(e, a, c), u = typeof a == "string" ? r.protocol.requests.get(a) : void 0;
|
|
22
|
+
return !u || typeof l != "function" ? l : (...r) => o.isClosed() ? i.isStreamSchema(u.successSchema) ? n.fromEffect(t.interrupt) : t.interrupt : s(Reflect.apply(l, e, r));
|
|
23
|
+
} }))), l))),
|
|
24
|
+
registerSingleton: (n, r, i) => e(o, t.suspend(() => a.registerSingleton(n, e(o, r), i)))
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
//#endregion
|
|
28
|
+
export { a as withJournalRoutingGuard };
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { makeJournalRoutingGuard as e } from "./journalRoutingGuard.js";
|
|
2
|
+
import { workflowJournalRoutingRowId as t, workflowJournalRoutingTable as n } from "./journalRoutingTable.js";
|
|
3
|
+
import { journalRoutingLayout as r, journalRoutingTransitions as i } from "./journalRoutingLayout.js";
|
|
4
|
+
import { withJournalRoutingTransaction as a } from "./journalRoutingTransaction.js";
|
|
5
|
+
import { resolvePostgresJournalLocation as o, resolvePostgresJournalNamespace as s } from "./journalRoutingNamespace.js";
|
|
6
|
+
import { acquireJournalRoutingLock as c } from "./journalRoutingLock.js";
|
|
7
|
+
import { JournalRoutingMaintenance as l, relocateWorkflowJournal as u } from "./workflowShardRelocationSql.js";
|
|
8
|
+
import { makePostgresJournalRoutingMaintenance as d } from "./journalRoutingMaintenance.js";
|
|
9
|
+
import { Effect as f, Option as p } from "effect";
|
|
10
|
+
import { SqlClient as m } from "effect/sql";
|
|
11
|
+
//#region src/journalRoutingState.ts
|
|
12
|
+
var h = (e, t) => f.gen(function* () {
|
|
13
|
+
let r = yield* e`SELECT c.relkind AS kind
|
|
14
|
+
FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
15
|
+
WHERE n.nspname = ${t} AND c.relname = ${n.tableName}`;
|
|
16
|
+
return r.length === 0 ? !1 : r.length !== 1 || r[0]?.kind !== "r" ? yield* f.fail(/* @__PURE__ */ Error("Journal routing metadata must be a table in the journal schema")) : !0;
|
|
17
|
+
}), g = (e) => {
|
|
18
|
+
if (!Number.isSafeInteger(e.generation) || e.generation < 0 || e.generation >= 2 ** 53 - 1 || !/^[a-z][a-z0-9._-]{0,63}$/.test(e.layout)) throw Error("Invalid journal routing state");
|
|
19
|
+
return r(e.layout), Object.freeze({
|
|
20
|
+
generation: e.generation,
|
|
21
|
+
layout: e.layout
|
|
22
|
+
});
|
|
23
|
+
}, _ = (e) => f.gen(function* () {
|
|
24
|
+
let n = yield* f.sync(() => g(e.expected)), r = yield* f.sync(() => g({
|
|
25
|
+
generation: n.generation + 1,
|
|
26
|
+
layout: e.nextLayout
|
|
27
|
+
})), a = yield* f.sync(() => i(n.layout, r.layout)), c = yield* m.SqlClient, p = c.withoutTransforms(), _ = yield* s, v = yield* d(_), y = l.of({ exclusive: (e) => v.exclusive(f.gen(function* () {
|
|
28
|
+
let i = yield* o;
|
|
29
|
+
if (i.namespace !== _) return yield* f.fail(/* @__PURE__ */ Error("Journal namespace changed during maintenance acquisition"));
|
|
30
|
+
if (yield* p`SELECT pg_advisory_xact_lock(6322741009312602::bigint)`, !(yield* h(p, i.schema))) return yield* f.fail(/* @__PURE__ */ Error("Workflow journal routing table is missing; apply the app schema first"));
|
|
31
|
+
yield* p`INSERT INTO ${i.routingTable} (id, namespace, generation, layout, relocation)
|
|
32
|
+
VALUES (${t(_)}, ${_}, 0, 'default', '[]') ON CONFLICT (namespace) DO NOTHING`;
|
|
33
|
+
let [s] = yield* p`
|
|
34
|
+
SELECT generation, layout FROM ${i.routingTable} WHERE namespace = ${_} FOR UPDATE`;
|
|
35
|
+
if (!s || String(s.generation) !== String(n.generation) || s.layout !== n.layout) return yield* f.fail(/* @__PURE__ */ Error("Journal routing generation changed; transition refused"));
|
|
36
|
+
let c = yield* e;
|
|
37
|
+
return yield* p`UPDATE ${i.routingTable} SET generation = ${r.generation}, layout = ${r.layout},
|
|
38
|
+
relocation = ${JSON.stringify(a)} WHERE namespace = ${_}`, c;
|
|
39
|
+
}).pipe(f.provideService(m.SqlClient, c))) });
|
|
40
|
+
return {
|
|
41
|
+
...yield* u(a).pipe(f.provideService(l, y)),
|
|
42
|
+
state: r
|
|
43
|
+
};
|
|
44
|
+
}), v = () => f.gen(function* () {
|
|
45
|
+
let e = yield* m.SqlClient;
|
|
46
|
+
if (p.isSome(yield* f.serviceOption(e.transactionService))) return yield* f.fail(/* @__PURE__ */ Error("Journal routing admission cannot enter an ambient transaction"));
|
|
47
|
+
if (!e.onDialectOrElse({
|
|
48
|
+
pg: () => !0,
|
|
49
|
+
orElse: () => !1
|
|
50
|
+
})) return yield* f.fail(/* @__PURE__ */ Error("Journal routing generation admission currently requires PostgreSQL"));
|
|
51
|
+
let t = yield* s, n = yield* c({
|
|
52
|
+
namespace: t,
|
|
53
|
+
mode: "shared"
|
|
54
|
+
}), r = yield* a(e, n.connection, f.gen(function* () {
|
|
55
|
+
let n = yield* o;
|
|
56
|
+
if (n.namespace !== t) return yield* f.fail(/* @__PURE__ */ Error("Journal namespace changed during runtime admission"));
|
|
57
|
+
if (!(yield* h(e, n.schema))) return {
|
|
58
|
+
generation: 0,
|
|
59
|
+
layout: "default"
|
|
60
|
+
};
|
|
61
|
+
let r = yield* e`
|
|
62
|
+
SELECT generation, layout FROM ${n.routingTable} WHERE namespace = ${t}`;
|
|
63
|
+
return r.length === 0 ? {
|
|
64
|
+
generation: 0,
|
|
65
|
+
layout: "default"
|
|
66
|
+
} : r.length === 1 ? yield* f.sync(() => g({
|
|
67
|
+
generation: Number(r[0]?.generation),
|
|
68
|
+
layout: String(r[0]?.layout)
|
|
69
|
+
})) : yield* f.fail(/* @__PURE__ */ Error("Journal routing metadata has duplicate namespace rows"));
|
|
70
|
+
}));
|
|
71
|
+
return {
|
|
72
|
+
...n,
|
|
73
|
+
state: r,
|
|
74
|
+
namespace: t
|
|
75
|
+
};
|
|
76
|
+
}), y = f.gen(function* () {
|
|
77
|
+
let e = yield* v();
|
|
78
|
+
return {
|
|
79
|
+
namespace: e.namespace,
|
|
80
|
+
state: e.state
|
|
81
|
+
};
|
|
82
|
+
}), b = (e) => f.gen(function* () {
|
|
83
|
+
let t = yield* f.sync(() => g(e)), n = yield* v();
|
|
84
|
+
return n.state.generation !== t.generation || n.state.layout !== t.layout ? yield* f.fail(/* @__PURE__ */ Error("Journal routing generation does not match this runtime")) : n;
|
|
85
|
+
}), x = (t) => f.gen(function* () {
|
|
86
|
+
let n = yield* b(t), r = yield* e({ verify: n.verify });
|
|
87
|
+
return {
|
|
88
|
+
...n,
|
|
89
|
+
...r
|
|
90
|
+
};
|
|
91
|
+
});
|
|
92
|
+
//#endregion
|
|
93
|
+
export { x as acquireGuardedPostgresJournalRoutingAdmission, b as acquirePostgresJournalRoutingAdmission, g as captureJournalRoutingState, y as readPostgresJournalRoutingState, _ as transitionPostgresJournalRouting };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { bigint as e, derivedRowId as t, id as n, table as r, text as i } from "@voltro/database";
|
|
2
|
+
//#region src/journalRoutingTable.ts
|
|
3
|
+
var a = r("_voltro_workflow_journal_routing", {
|
|
4
|
+
id: n({ prefix: "wfjr" }),
|
|
5
|
+
namespace: i(),
|
|
6
|
+
generation: e(),
|
|
7
|
+
layout: i(),
|
|
8
|
+
relocation: i()
|
|
9
|
+
}).unique(["namespace"]).nonReactive(), o = (e) => t("wfjr", e);
|
|
10
|
+
//#endregion
|
|
11
|
+
export { o as workflowJournalRoutingRowId, a as workflowJournalRoutingTable };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Effect as e } from "effect";
|
|
2
|
+
import { SqlClient as t } from "effect/sql";
|
|
3
|
+
//#region src/journalRoutingTransaction.ts
|
|
4
|
+
var n = (n, r, i) => t.makeWithTransaction({
|
|
5
|
+
transactionService: n.transactionService,
|
|
6
|
+
spanAttributes: [],
|
|
7
|
+
acquireConnection: e.succeed([void 0, r]),
|
|
8
|
+
begin: (t) => t.executeUnprepared("BEGIN", [], void 0).pipe(e.asVoid),
|
|
9
|
+
commit: (t) => t.executeUnprepared("COMMIT", [], void 0).pipe(e.asVoid),
|
|
10
|
+
rollback: (t) => t.executeUnprepared("ROLLBACK", [], void 0).pipe(e.asVoid),
|
|
11
|
+
savepoint: (t, n) => t.executeUnprepared(`SAVEPOINT voltro_routing_${n}`, [], void 0).pipe(e.asVoid),
|
|
12
|
+
rollbackSavepoint: (t, n) => t.executeUnprepared(`ROLLBACK TO SAVEPOINT voltro_routing_${n}`, [], void 0).pipe(e.asVoid),
|
|
13
|
+
releaseSavepoint: (t, n) => t.executeUnprepared(`RELEASE SAVEPOINT voltro_routing_${n}`, [], void 0).pipe(e.asVoid)
|
|
14
|
+
})(i);
|
|
15
|
+
//#endregion
|
|
16
|
+
export { n as withJournalRoutingTransaction };
|
package/dist/messages.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { openEventPayload as e } from "./journalEncryption.js";
|
|
2
|
+
import { eq as t } from "@voltro/database";
|
|
3
|
+
//#region src/messages.ts
|
|
4
|
+
var n = (e) => new Promise((t) => setTimeout(t, e)), r = () => {
|
|
5
|
+
let e = globalThis.crypto;
|
|
6
|
+
return typeof e?.randomUUID == "function" ? e.randomUUID() : `${Date.now().toString(36)}${Math.random().toString(36).slice(2)}`;
|
|
7
|
+
}, i = () => `wfu_${r()}`, a = async (e, n) => {
|
|
8
|
+
let r = n.id ?? n.executionId;
|
|
9
|
+
if (!r) throw Error("workflow message target requires target.id or target.executionId");
|
|
10
|
+
let i = await e.query({
|
|
11
|
+
table: "_voltro_workflow_runs",
|
|
12
|
+
order: [],
|
|
13
|
+
predicate: t("id", r),
|
|
14
|
+
projection: void 0,
|
|
15
|
+
skip: void 0,
|
|
16
|
+
take: 1
|
|
17
|
+
});
|
|
18
|
+
if (i[0]) return i[0];
|
|
19
|
+
let a = (await e.query({
|
|
20
|
+
table: "_voltro_workflow_runs",
|
|
21
|
+
order: [],
|
|
22
|
+
predicate: t("executionId", r),
|
|
23
|
+
projection: void 0,
|
|
24
|
+
skip: void 0,
|
|
25
|
+
take: 1
|
|
26
|
+
}))[0];
|
|
27
|
+
if (!a) throw Error(`workflow message target not found: ${r}`);
|
|
28
|
+
return a;
|
|
29
|
+
}, o = class extends Error {
|
|
30
|
+
runId;
|
|
31
|
+
eventType;
|
|
32
|
+
eventId;
|
|
33
|
+
_tag = "WorkflowMessageNotRecorded";
|
|
34
|
+
constructor(e, t, n) {
|
|
35
|
+
super(`workflow ${t} for run ${e} was NOT recorded (event ${n}): the run will not see it — the store refused the row, see the recorder's warning`), this.runId = e, this.eventType = t, this.eventId = n, this.name = "WorkflowMessageNotRecorded";
|
|
36
|
+
}
|
|
37
|
+
}, s = async (e) => {
|
|
38
|
+
let t = await a(e.store, e.target), n = await e.recorder.recordEvent({
|
|
39
|
+
runId: t.id,
|
|
40
|
+
eventType: "signal-sent",
|
|
41
|
+
payload: {
|
|
42
|
+
signalName: e.signalName,
|
|
43
|
+
value: e.payload
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
if (n.recorded === !1) throw new o(t.id, "signal-sent", n.id);
|
|
47
|
+
return { eventId: n.id };
|
|
48
|
+
}, c = async (r) => {
|
|
49
|
+
let s = await a(r.store, r.target), c = i(), l = await r.recorder.recordEvent({
|
|
50
|
+
runId: s.id,
|
|
51
|
+
eventType: "update-requested",
|
|
52
|
+
payload: {
|
|
53
|
+
updateId: c,
|
|
54
|
+
updateName: r.updateName,
|
|
55
|
+
value: r.payload
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
if (l.recorded === !1) throw new o(s.id, "update-requested", l.id);
|
|
59
|
+
let u = Date.now(), d = r.options?.timeoutMs ?? 3e4, f = r.options?.pollIntervalMs ?? 100;
|
|
60
|
+
for (;;) {
|
|
61
|
+
let i = {
|
|
62
|
+
table: "_voltro_workflow_run_events",
|
|
63
|
+
order: [{
|
|
64
|
+
column: "occurredAt",
|
|
65
|
+
direction: "asc"
|
|
66
|
+
}],
|
|
67
|
+
predicate: t("runId", s.id),
|
|
68
|
+
projection: void 0,
|
|
69
|
+
skip: void 0,
|
|
70
|
+
take: 1e3
|
|
71
|
+
}, a = await r.store.query(i), o = a.find((e) => e.eventType === "update-completed" && e.payload?.updateId === c);
|
|
72
|
+
if (o) return {
|
|
73
|
+
eventId: l.id,
|
|
74
|
+
updateId: c,
|
|
75
|
+
completedEventId: o.id,
|
|
76
|
+
result: e(o.payload)?.result
|
|
77
|
+
};
|
|
78
|
+
let p = a.find((e) => e.eventType === "update-failed" && e.payload?.updateId === c);
|
|
79
|
+
if (p) {
|
|
80
|
+
let t = Error(e(p.payload)?.errorMessage ?? `workflow update '${r.updateName}' failed`);
|
|
81
|
+
throw Object.assign(t, {
|
|
82
|
+
updateId: c,
|
|
83
|
+
eventId: l.id,
|
|
84
|
+
errorTag: p.payload?.errorTag ?? null
|
|
85
|
+
}), t;
|
|
86
|
+
}
|
|
87
|
+
if (Date.now() - u >= d) throw Error(`Timed out waiting for workflow update '${r.updateName}' (${c})`);
|
|
88
|
+
await n(f);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
//#endregion
|
|
92
|
+
export { o as WorkflowMessageNotRecorded, i as makeWorkflowUpdateId, a as resolveWorkflowMessageRun, s as sendWorkflowSignal, c as sendWorkflowUpdate };
|