rivetkit 2.3.3 → 2.3.5-rc.1
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/dist/browser/client.d.ts +157 -9
- package/dist/browser/client.js +518 -542
- package/dist/browser/client.js.map +1 -1
- package/dist/browser/inspector/client.d.ts +101 -2
- package/dist/browser/inspector/client.js +1245 -227
- package/dist/browser/inspector/client.js.map +1 -1
- package/dist/tsup/agent-os/index.cjs +103 -36
- package/dist/tsup/agent-os/index.cjs.map +1 -1
- package/dist/tsup/agent-os/index.d.cts +159 -11
- package/dist/tsup/agent-os/index.d.ts +159 -11
- package/dist/tsup/agent-os/index.js +103 -36
- package/dist/tsup/agent-os/index.js.map +1 -1
- package/dist/tsup/{chunk-34P567PO.cjs → chunk-4XKED5P5.cjs} +145 -176
- package/dist/tsup/chunk-4XKED5P5.cjs.map +1 -0
- package/dist/tsup/{chunk-PYO2U53V.cjs → chunk-6HQCLWAW.cjs} +384 -4
- package/dist/tsup/chunk-6HQCLWAW.cjs.map +1 -0
- package/dist/tsup/{chunk-JZ7TWV65.js → chunk-7AFZMFPQ.js} +15 -1
- package/dist/tsup/chunk-7AFZMFPQ.js.map +1 -0
- package/dist/tsup/{chunk-BLDO2FKO.js → chunk-B4IZU537.js} +382 -2
- package/dist/tsup/chunk-B4IZU537.js.map +1 -0
- package/dist/tsup/{chunk-3MHDOUD7.cjs → chunk-G3CCRCTK.cjs} +14 -9
- package/dist/tsup/chunk-G3CCRCTK.cjs.map +1 -0
- package/dist/tsup/{chunk-CXRPENO3.js → chunk-GAV4PKFT.js} +15 -46
- package/dist/tsup/{chunk-CXRPENO3.js.map → chunk-GAV4PKFT.js.map} +1 -1
- package/dist/tsup/{chunk-HXUEHHJF.js → chunk-JI6GZ2C2.js} +2 -11
- package/dist/tsup/{chunk-HXUEHHJF.js.map → chunk-JI6GZ2C2.js.map} +1 -1
- package/dist/tsup/{chunk-YUEC5SEY.cjs → chunk-M3FCXL3Q.cjs} +3 -3
- package/dist/tsup/{chunk-YUEC5SEY.cjs.map → chunk-M3FCXL3Q.cjs.map} +1 -1
- package/dist/tsup/{chunk-KEKWJECX.js → chunk-MGTSVSUC.js} +2 -2
- package/dist/tsup/{chunk-VE2X4KMG.cjs → chunk-MYWZCDML.cjs} +2 -11
- package/dist/tsup/chunk-MYWZCDML.cjs.map +1 -0
- package/dist/tsup/{chunk-DFA7SYSW.js → chunk-NIC3QLKL.js} +3 -3
- package/dist/tsup/{chunk-BZM4PMFS.js → chunk-P4OGQ4JL.js} +5 -7
- package/dist/tsup/{chunk-BZM4PMFS.js.map → chunk-P4OGQ4JL.js.map} +1 -1
- package/dist/tsup/{chunk-NT2NK3VT.js → chunk-PAG6G46L.js} +2 -2
- package/dist/tsup/{chunk-XIX5DOZN.js → chunk-SHBE77IT.js} +14 -9
- package/dist/tsup/chunk-SHBE77IT.js.map +1 -0
- package/dist/tsup/{chunk-TYLP3U4Y.cjs → chunk-TNIWIUNV.cjs} +9 -11
- package/dist/tsup/chunk-TNIWIUNV.cjs.map +1 -0
- package/dist/tsup/{chunk-S644FL73.cjs → chunk-TR5NLR5V.cjs} +4 -4
- package/dist/tsup/{chunk-S644FL73.cjs.map → chunk-TR5NLR5V.cjs.map} +1 -1
- package/dist/tsup/{chunk-ZA7FLHKH.cjs → chunk-UEULFXUI.cjs} +16 -2
- package/dist/tsup/chunk-UEULFXUI.cjs.map +1 -0
- package/dist/tsup/{chunk-X63ROSOG.cjs → chunk-UJ2FQY63.cjs} +7 -7
- package/dist/tsup/{chunk-X63ROSOG.cjs.map → chunk-UJ2FQY63.cjs.map} +1 -1
- package/dist/tsup/client/mod.cjs +7 -8
- package/dist/tsup/client/mod.cjs.map +1 -1
- package/dist/tsup/client/mod.d.cts +5 -4
- package/dist/tsup/client/mod.d.ts +5 -4
- package/dist/tsup/client/mod.js +6 -7
- package/dist/tsup/common/log.cjs +2 -2
- package/dist/tsup/common/log.js +1 -1
- package/dist/tsup/common/websocket.cjs +3 -3
- package/dist/tsup/common/websocket.js +2 -2
- package/dist/tsup/{config-D49x8NpL.d.cts → config-BxOimoGX.d.cts} +16 -0
- package/dist/tsup/{config-D49x8NpL.d.ts → config-BxOimoGX.d.ts} +16 -0
- package/dist/tsup/{config-ZkIsRFsN.d.ts → config-BzdqbLAP.d.ts} +164 -27
- package/dist/tsup/{config-BfBhjEbk.d.cts → config-CPPEwn_e.d.cts} +164 -27
- package/dist/tsup/{context-sZ9GlaBK.d.cts → context-DSA9gFXB.d.cts} +2 -2
- package/dist/tsup/{context-B7-84u9K.d.ts → context-wWv-K2K_.d.ts} +2 -2
- package/dist/tsup/db/drizzle.cjs +120 -68
- package/dist/tsup/db/drizzle.cjs.map +1 -1
- package/dist/tsup/db/drizzle.d.cts +8 -3
- package/dist/tsup/db/drizzle.d.ts +8 -3
- package/dist/tsup/db/drizzle.js +120 -68
- package/dist/tsup/db/drizzle.js.map +1 -1
- package/dist/tsup/db/mod.cjs +74 -22
- package/dist/tsup/db/mod.cjs.map +1 -1
- package/dist/tsup/db/mod.d.cts +4 -3
- package/dist/tsup/db/mod.d.ts +4 -3
- package/dist/tsup/db/mod.js +74 -22
- package/dist/tsup/db/mod.js.map +1 -1
- package/dist/tsup/dynamic/mod.cjs +2 -2
- package/dist/tsup/dynamic/mod.d.cts +3 -3
- package/dist/tsup/dynamic/mod.d.ts +3 -3
- package/dist/tsup/dynamic/mod.js +1 -1
- package/dist/tsup/inspector/mod.cjs +4 -5
- package/dist/tsup/inspector/mod.cjs.map +1 -1
- package/dist/tsup/inspector/mod.js +3 -4
- package/dist/tsup/inspector/mod.js.map +1 -1
- package/dist/tsup/inspector-tab/mod.cjs +2 -2
- package/dist/tsup/inspector-tab/mod.cjs.map +1 -1
- package/dist/tsup/inspector-tab/mod.d.cts +5 -5
- package/dist/tsup/inspector-tab/mod.d.ts +5 -5
- package/dist/tsup/inspector-tab/mod.js +1 -1
- package/dist/tsup/inspector-tab/mod.js.map +1 -1
- package/dist/tsup/mod.cjs +605 -158
- package/dist/tsup/mod.cjs.map +1 -1
- package/dist/tsup/mod.d.cts +5 -5
- package/dist/tsup/mod.d.ts +5 -5
- package/dist/tsup/mod.js +528 -81
- package/dist/tsup/mod.js.map +1 -1
- package/dist/tsup/test/mod.cjs +10 -11
- package/dist/tsup/test/mod.cjs.map +1 -1
- package/dist/tsup/test/mod.d.cts +3 -3
- package/dist/tsup/test/mod.d.ts +3 -3
- package/dist/tsup/test/mod.js +6 -7
- package/dist/tsup/test/mod.js.map +1 -1
- package/dist/tsup/utils-CV0akuDD.d.ts +162 -0
- package/dist/tsup/utils-DQDCphrl.d.cts +162 -0
- package/dist/tsup/utils.cjs +6 -2
- package/dist/tsup/utils.cjs.map +1 -1
- package/dist/tsup/utils.d.cts +3 -146
- package/dist/tsup/utils.d.ts +3 -146
- package/dist/tsup/utils.js +5 -1
- package/dist/tsup/workflow/mod.cjs +198 -151
- package/dist/tsup/workflow/mod.cjs.map +1 -1
- package/dist/tsup/workflow/mod.d.cts +5 -5
- package/dist/tsup/workflow/mod.d.ts +5 -5
- package/dist/tsup/workflow/mod.js +187 -140
- package/dist/tsup/workflow/mod.js.map +1 -1
- package/package.json +8 -8
- package/src/actor/config.test.ts +14 -0
- package/src/actor/config.ts +104 -16
- package/src/actor/definition.ts +18 -7
- package/src/agent-os/actor/index.ts +2 -2
- package/src/common/bare/generated/actor-runtime-socket-protocol/v1.ts +848 -0
- package/src/common/bare/generated/inspector/v6.ts +1367 -0
- package/src/common/database/config.ts +24 -0
- package/src/common/database/mod.test.ts +148 -59
- package/src/common/database/mod.ts +93 -23
- package/src/common/database/native-database.test.ts +9 -0
- package/src/common/database/native-database.ts +151 -0
- package/src/common/database/shared.ts +15 -0
- package/src/common/encoding.ts +28 -21
- package/src/db/drizzle.test.ts +157 -0
- package/src/db/drizzle.ts +170 -79
- package/src/dynamic/isolate-runtime.ts +0 -2
- package/src/engine-client/driver.ts +0 -15
- package/src/engine-client/mod.ts +0 -41
- package/src/inspector/client.browser.ts +69 -8
- package/src/inspector-tab/mod.ts +1 -0
- package/src/registry/config/index.ts +1 -35
- package/src/registry/napi-runtime.ts +204 -16
- package/src/registry/native.ts +200 -30
- package/src/registry/runtime.ts +146 -3
- package/src/registry/wasm-runtime.ts +217 -6
- package/src/utils.ts +3 -0
- package/src/workflow/context.ts +5 -27
- package/src/workflow/driver.test.ts +62 -0
- package/src/workflow/driver.ts +231 -113
- package/src/workflow/mod.ts +3 -3
- package/dist/tsup/chunk-34P567PO.cjs.map +0 -1
- package/dist/tsup/chunk-3MHDOUD7.cjs.map +0 -1
- package/dist/tsup/chunk-APW73HCH.cjs +0 -382
- package/dist/tsup/chunk-APW73HCH.cjs.map +0 -1
- package/dist/tsup/chunk-BLDO2FKO.js.map +0 -1
- package/dist/tsup/chunk-DHXWD4DF.js +0 -382
- package/dist/tsup/chunk-DHXWD4DF.js.map +0 -1
- package/dist/tsup/chunk-JZ7TWV65.js.map +0 -1
- package/dist/tsup/chunk-PYO2U53V.cjs.map +0 -1
- package/dist/tsup/chunk-TYLP3U4Y.cjs.map +0 -1
- package/dist/tsup/chunk-VE2X4KMG.cjs.map +0 -1
- package/dist/tsup/chunk-XIX5DOZN.js.map +0 -1
- package/dist/tsup/chunk-ZA7FLHKH.cjs.map +0 -1
- package/src/actor/driver.ts +0 -141
- package/src/actor/instance/mod.ts +0 -2484
- package/src/drivers/engine/actor-driver.ts +0 -2473
- /package/dist/tsup/{chunk-KEKWJECX.js.map → chunk-MGTSVSUC.js.map} +0 -0
- /package/dist/tsup/{chunk-DFA7SYSW.js.map → chunk-NIC3QLKL.js.map} +0 -0
- /package/dist/tsup/{chunk-NT2NK3VT.js.map → chunk-PAG6G46L.js.map} +0 -0
package/src/workflow/driver.ts
CHANGED
|
@@ -8,8 +8,14 @@ import type {
|
|
|
8
8
|
import type { RunContext } from "@/actor/config";
|
|
9
9
|
import type { AnyStaticActorInstance } from "@/actor/definition";
|
|
10
10
|
import { makeWorkflowKey, workflowStoragePrefix } from "@/actor/keys";
|
|
11
|
+
import type { SqliteDatabase } from "@/common/database/config";
|
|
11
12
|
|
|
12
13
|
const WORKFLOW_STORAGE_PREFIX = workflowStoragePrefix();
|
|
14
|
+
// Keep workflow flushes below depot's 320-dirty-page commit ceiling. The
|
|
15
|
+
// former actor-KV transport allowed 976 KiB batches; SQLite also dirties table
|
|
16
|
+
// and index pages, so it needs the same conservative budget as core imports.
|
|
17
|
+
const WORKFLOW_SQLITE_MAX_BATCH_ROWS = 128;
|
|
18
|
+
const WORKFLOW_SQLITE_MAX_BATCH_BYTES = 512 * 1024;
|
|
13
19
|
|
|
14
20
|
// Mirrors the element shape returned by `queueManager.receive`. The actor
|
|
15
21
|
// instance is reached through a loose type here, so the call's result is
|
|
@@ -22,8 +28,6 @@ interface ReceivedQueueMessage {
|
|
|
22
28
|
complete?: (response?: unknown) => Promise<void>;
|
|
23
29
|
}
|
|
24
30
|
|
|
25
|
-
// `kvListPrefix` returns key/value tuples, but the loose actor type erases that
|
|
26
|
-
// so the tuple destructures need an explicit annotation.
|
|
27
31
|
type KVEntryTuple = [Uint8Array, Uint8Array];
|
|
28
32
|
|
|
29
33
|
function stripWorkflowKey(prefixed: Uint8Array): Uint8Array {
|
|
@@ -41,6 +45,206 @@ function computeUpperBound(prefix: Uint8Array): Uint8Array | null {
|
|
|
41
45
|
return null;
|
|
42
46
|
}
|
|
43
47
|
|
|
48
|
+
function normalizeSqlBlob(value: unknown): Uint8Array {
|
|
49
|
+
if (value instanceof Uint8Array) {
|
|
50
|
+
return value;
|
|
51
|
+
}
|
|
52
|
+
if (value instanceof ArrayBuffer) {
|
|
53
|
+
return new Uint8Array(value);
|
|
54
|
+
}
|
|
55
|
+
if (ArrayBuffer.isView(value)) {
|
|
56
|
+
return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
|
|
57
|
+
}
|
|
58
|
+
if (Array.isArray(value)) {
|
|
59
|
+
const bytes = new Uint8Array(value.length);
|
|
60
|
+
for (const [i, item] of value.entries()) {
|
|
61
|
+
if (!Number.isInteger(item) || item < 0 || item > 255) {
|
|
62
|
+
throw new Error("workflow sqlite value was not a byte array");
|
|
63
|
+
}
|
|
64
|
+
bytes[i] = item;
|
|
65
|
+
}
|
|
66
|
+
return bytes;
|
|
67
|
+
}
|
|
68
|
+
throw new Error("workflow sqlite value was not a blob");
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function runtimeSqlFromContext(
|
|
72
|
+
runCtx?: RunContext<any, any, any, any, any, any, any, any>,
|
|
73
|
+
): SqliteDatabase | undefined {
|
|
74
|
+
const sql = (runCtx as unknown as { sql?: unknown } | undefined)?.sql;
|
|
75
|
+
if (
|
|
76
|
+
sql &&
|
|
77
|
+
typeof sql === "object" &&
|
|
78
|
+
"query" in sql &&
|
|
79
|
+
"execute" in sql &&
|
|
80
|
+
"executeBatch" in sql &&
|
|
81
|
+
"run" in sql
|
|
82
|
+
) {
|
|
83
|
+
return sql as SqliteDatabase;
|
|
84
|
+
}
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
type WorkflowSqliteDatabase = SqliteDatabase &
|
|
89
|
+
Required<Pick<SqliteDatabase, "executeBatch">>;
|
|
90
|
+
|
|
91
|
+
class WorkflowStorage {
|
|
92
|
+
#sql: WorkflowSqliteDatabase;
|
|
93
|
+
|
|
94
|
+
constructor(sql?: SqliteDatabase) {
|
|
95
|
+
if (!sql) {
|
|
96
|
+
throw new Error(
|
|
97
|
+
"workflow storage requires embedded SQLite; actor KV workflow storage is no longer supported",
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
if (!sql.executeBatch) {
|
|
101
|
+
throw new Error(
|
|
102
|
+
"workflow storage requires a SQLite database with executeBatch support",
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
this.#sql = sql as WorkflowSqliteDatabase;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async get(key: Uint8Array): Promise<Uint8Array | null> {
|
|
109
|
+
const prefixed = makeWorkflowKey(key);
|
|
110
|
+
const result = await this.#sql.query(
|
|
111
|
+
"SELECT value FROM _rivet_wf_kv WHERE key = ?",
|
|
112
|
+
[prefixed],
|
|
113
|
+
);
|
|
114
|
+
return result.rows[0]?.[0] == null
|
|
115
|
+
? null
|
|
116
|
+
: normalizeSqlBlob(result.rows[0][0]);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async set(key: Uint8Array, value: Uint8Array): Promise<void> {
|
|
120
|
+
await this.batch([{ key, value }]);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async delete(key: Uint8Array): Promise<void> {
|
|
124
|
+
const prefixed = makeWorkflowKey(key);
|
|
125
|
+
await this.#sql.run("DELETE FROM _rivet_wf_kv WHERE key = ?", [
|
|
126
|
+
prefixed,
|
|
127
|
+
]);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async deletePrefix(prefix: Uint8Array): Promise<void> {
|
|
131
|
+
const start = makeWorkflowKey(prefix);
|
|
132
|
+
const end = computeUpperBound(start);
|
|
133
|
+
if (end) {
|
|
134
|
+
await this.#sql.run(
|
|
135
|
+
"DELETE FROM _rivet_wf_kv WHERE key >= ? AND key < ?",
|
|
136
|
+
[start, end],
|
|
137
|
+
);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const entries = await this.listRaw(start);
|
|
141
|
+
await this.deleteRawKeys(
|
|
142
|
+
entries
|
|
143
|
+
.filter(([key]) => keyStartsWith(key, start))
|
|
144
|
+
.map(([key]) => key),
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async deleteRange(start: Uint8Array, end: Uint8Array): Promise<void> {
|
|
149
|
+
const prefixedStart = makeWorkflowKey(start);
|
|
150
|
+
const prefixedEnd = makeWorkflowKey(end);
|
|
151
|
+
await this.#sql.run(
|
|
152
|
+
"DELETE FROM _rivet_wf_kv WHERE key >= ? AND key < ?",
|
|
153
|
+
[prefixedStart, prefixedEnd],
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
async list(prefix: Uint8Array): Promise<KVEntry[]> {
|
|
158
|
+
const prefixed = makeWorkflowKey(prefix);
|
|
159
|
+
const entries = await this.listRaw(prefixed);
|
|
160
|
+
return entries
|
|
161
|
+
.filter(([key]) => keyStartsWith(key, prefixed))
|
|
162
|
+
.map(([key, value]: KVEntryTuple) => ({
|
|
163
|
+
key: stripWorkflowKey(key),
|
|
164
|
+
value,
|
|
165
|
+
}));
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
async batch(writes: KVWrite[]): Promise<void> {
|
|
169
|
+
if (writes.length === 0) return;
|
|
170
|
+
for (const chunk of chunkWorkflowWrites(writes)) {
|
|
171
|
+
await this.#sql.executeBatch(
|
|
172
|
+
chunk.map(({ key, value }) => ({
|
|
173
|
+
sql: "INSERT INTO _rivet_wf_kv (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value",
|
|
174
|
+
params: [makeWorkflowKey(key), value],
|
|
175
|
+
})),
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
async listRaw(prefix: Uint8Array): Promise<KVEntryTuple[]> {
|
|
181
|
+
const end = computeUpperBound(prefix);
|
|
182
|
+
const result = end
|
|
183
|
+
? await this.#sql.query(
|
|
184
|
+
"SELECT key, value FROM _rivet_wf_kv WHERE key >= ? AND key < ? ORDER BY key ASC",
|
|
185
|
+
[prefix, end],
|
|
186
|
+
)
|
|
187
|
+
: await this.#sql.query(
|
|
188
|
+
"SELECT key, value FROM _rivet_wf_kv WHERE key >= ? ORDER BY key ASC",
|
|
189
|
+
[prefix],
|
|
190
|
+
);
|
|
191
|
+
return result.rows.map((row) => [
|
|
192
|
+
normalizeSqlBlob(row[0]),
|
|
193
|
+
normalizeSqlBlob(row[1]),
|
|
194
|
+
]);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
async deleteRawKeys(keys: Uint8Array[]): Promise<void> {
|
|
198
|
+
for (
|
|
199
|
+
let start = 0;
|
|
200
|
+
start < keys.length;
|
|
201
|
+
start += WORKFLOW_SQLITE_MAX_BATCH_ROWS
|
|
202
|
+
) {
|
|
203
|
+
await this.#sql.executeBatch(
|
|
204
|
+
keys
|
|
205
|
+
.slice(start, start + WORKFLOW_SQLITE_MAX_BATCH_ROWS)
|
|
206
|
+
.map((key) => ({
|
|
207
|
+
sql: "DELETE FROM _rivet_wf_kv WHERE key = ?",
|
|
208
|
+
params: [key],
|
|
209
|
+
})),
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export function chunkWorkflowWrites(writes: KVWrite[]): KVWrite[][] {
|
|
216
|
+
const chunks: KVWrite[][] = [];
|
|
217
|
+
let chunk: KVWrite[] = [];
|
|
218
|
+
let chunkBytes = 0;
|
|
219
|
+
for (const write of writes) {
|
|
220
|
+
const writeBytes =
|
|
221
|
+
WORKFLOW_STORAGE_PREFIX.length +
|
|
222
|
+
write.key.length +
|
|
223
|
+
write.value.length;
|
|
224
|
+
if (
|
|
225
|
+
chunk.length > 0 &&
|
|
226
|
+
(chunk.length >= WORKFLOW_SQLITE_MAX_BATCH_ROWS ||
|
|
227
|
+
chunkBytes + writeBytes > WORKFLOW_SQLITE_MAX_BATCH_BYTES)
|
|
228
|
+
) {
|
|
229
|
+
chunks.push(chunk);
|
|
230
|
+
chunk = [];
|
|
231
|
+
chunkBytes = 0;
|
|
232
|
+
}
|
|
233
|
+
chunk.push(write);
|
|
234
|
+
chunkBytes += writeBytes;
|
|
235
|
+
}
|
|
236
|
+
if (chunk.length > 0) chunks.push(chunk);
|
|
237
|
+
return chunks;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function keyStartsWith(key: Uint8Array, prefix: Uint8Array): boolean {
|
|
241
|
+
if (key.length < prefix.length) return false;
|
|
242
|
+
for (let i = 0; i < prefix.length; i++) {
|
|
243
|
+
if (key[i] !== prefix[i]) return false;
|
|
244
|
+
}
|
|
245
|
+
return true;
|
|
246
|
+
}
|
|
247
|
+
|
|
44
248
|
class ActorWorkflowMessageDriver implements WorkflowMessageDriver {
|
|
45
249
|
#actor: AnyStaticActorInstance;
|
|
46
250
|
#runCtx: RunContext<any, any, any, any, any, any, any, any>;
|
|
@@ -113,10 +317,12 @@ class ActorWorkflowMessageDriver implements WorkflowMessageDriver {
|
|
|
113
317
|
}
|
|
114
318
|
|
|
115
319
|
export class ActorWorkflowDriver implements EngineDriver {
|
|
320
|
+
readonly atomicBatch = true;
|
|
116
321
|
readonly workerPollInterval = 100;
|
|
117
322
|
readonly messageDriver: WorkflowMessageDriver;
|
|
118
323
|
#actor: AnyStaticActorInstance;
|
|
119
324
|
#runCtx: RunContext<any, any, any, any, any, any, any, any>;
|
|
325
|
+
#storage: WorkflowStorage;
|
|
120
326
|
|
|
121
327
|
constructor(
|
|
122
328
|
actor: AnyStaticActorInstance,
|
|
@@ -125,97 +331,42 @@ export class ActorWorkflowDriver implements EngineDriver {
|
|
|
125
331
|
this.#actor = actor;
|
|
126
332
|
this.#runCtx = runCtx;
|
|
127
333
|
this.messageDriver = new ActorWorkflowMessageDriver(actor, runCtx);
|
|
334
|
+
this.#storage = new WorkflowStorage(runtimeSqlFromContext(runCtx));
|
|
128
335
|
}
|
|
129
336
|
|
|
130
337
|
async get(key: Uint8Array): Promise<Uint8Array | null> {
|
|
131
|
-
|
|
132
|
-
this.#actor.driver.kvBatchGet(this.#actor.id, [
|
|
133
|
-
makeWorkflowKey(key),
|
|
134
|
-
]),
|
|
135
|
-
);
|
|
136
|
-
return value ?? null;
|
|
338
|
+
return await this.#runCtx.internalKeepAwake(this.#storage.get(key));
|
|
137
339
|
}
|
|
138
340
|
|
|
139
341
|
async set(key: Uint8Array, value: Uint8Array): Promise<void> {
|
|
140
|
-
await this.#runCtx.internalKeepAwake(
|
|
141
|
-
this.#actor.driver.kvBatchPut(this.#actor.id, [
|
|
142
|
-
[makeWorkflowKey(key), value],
|
|
143
|
-
]),
|
|
144
|
-
);
|
|
342
|
+
await this.#runCtx.internalKeepAwake(this.#storage.set(key, value));
|
|
145
343
|
}
|
|
146
344
|
|
|
147
345
|
async delete(key: Uint8Array): Promise<void> {
|
|
148
|
-
await this.#runCtx.internalKeepAwake(
|
|
149
|
-
this.#actor.driver.kvBatchDelete(this.#actor.id, [
|
|
150
|
-
makeWorkflowKey(key),
|
|
151
|
-
]),
|
|
152
|
-
);
|
|
346
|
+
await this.#runCtx.internalKeepAwake(this.#storage.delete(key));
|
|
153
347
|
}
|
|
154
348
|
|
|
155
349
|
async deletePrefix(prefix: Uint8Array): Promise<void> {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
await this.#runCtx.internalKeepAwake(
|
|
160
|
-
this.#actor.driver.kvDeleteRange(this.#actor.id, start, end),
|
|
161
|
-
);
|
|
162
|
-
} else {
|
|
163
|
-
const entries = await this.#runCtx.internalKeepAwake(
|
|
164
|
-
this.#actor.driver.kvListPrefix(this.#actor.id, start),
|
|
165
|
-
);
|
|
166
|
-
if (entries.length === 0) {
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
await this.#runCtx.internalKeepAwake(
|
|
170
|
-
this.#actor.driver.kvBatchDelete(
|
|
171
|
-
this.#actor.id,
|
|
172
|
-
entries.map(([key]: KVEntryTuple) => key),
|
|
173
|
-
),
|
|
174
|
-
);
|
|
175
|
-
}
|
|
350
|
+
await this.#runCtx.internalKeepAwake(
|
|
351
|
+
this.#storage.deletePrefix(prefix),
|
|
352
|
+
);
|
|
176
353
|
}
|
|
177
354
|
|
|
178
355
|
async deleteRange(start: Uint8Array, end: Uint8Array): Promise<void> {
|
|
179
356
|
await this.#runCtx.internalKeepAwake(
|
|
180
|
-
this.#
|
|
181
|
-
this.#actor.id,
|
|
182
|
-
makeWorkflowKey(start),
|
|
183
|
-
makeWorkflowKey(end),
|
|
184
|
-
),
|
|
357
|
+
this.#storage.deleteRange(start, end),
|
|
185
358
|
);
|
|
186
359
|
}
|
|
187
360
|
|
|
188
361
|
async list(prefix: Uint8Array): Promise<KVEntry[]> {
|
|
189
|
-
|
|
190
|
-
this.#actor.driver.kvListPrefix(
|
|
191
|
-
this.#actor.id,
|
|
192
|
-
makeWorkflowKey(prefix),
|
|
193
|
-
),
|
|
194
|
-
);
|
|
195
|
-
return entries.map(([key, value]: KVEntryTuple) => ({
|
|
196
|
-
key: stripWorkflowKey(key),
|
|
197
|
-
value,
|
|
198
|
-
}));
|
|
362
|
+
return await this.#runCtx.internalKeepAwake(this.#storage.list(prefix));
|
|
199
363
|
}
|
|
200
364
|
|
|
201
365
|
async batch(writes: KVWrite[]): Promise<void> {
|
|
202
366
|
if (writes.length === 0) return;
|
|
203
367
|
|
|
204
|
-
// Flush actor state together with workflow state to ensure atomicity.
|
|
205
|
-
// If the server crashes after workflow flush, actor state must also be persisted.
|
|
206
368
|
await this.#runCtx.internalKeepAwake(
|
|
207
|
-
|
|
208
|
-
this.#actor.driver.kvBatchPut(
|
|
209
|
-
this.#actor.id,
|
|
210
|
-
writes.map(({ key, value }) => [
|
|
211
|
-
makeWorkflowKey(key),
|
|
212
|
-
value,
|
|
213
|
-
]),
|
|
214
|
-
),
|
|
215
|
-
this.#actor.stateManager.saveState({
|
|
216
|
-
immediate: true,
|
|
217
|
-
}),
|
|
218
|
-
]),
|
|
369
|
+
this.#actor.stateManager.saveStateAndWorkflowBatch(writes),
|
|
219
370
|
);
|
|
220
371
|
}
|
|
221
372
|
|
|
@@ -267,68 +418,38 @@ export class ActorWorkflowControlDriver implements EngineDriver {
|
|
|
267
418
|
readonly messageDriver: WorkflowMessageDriver =
|
|
268
419
|
new NoopWorkflowMessageDriver();
|
|
269
420
|
#actor: AnyStaticActorInstance;
|
|
421
|
+
#storage: WorkflowStorage;
|
|
270
422
|
|
|
271
|
-
constructor(
|
|
423
|
+
constructor(
|
|
424
|
+
actor: AnyStaticActorInstance,
|
|
425
|
+
runCtx?: RunContext<any, any, any, any, any, any, any, any>,
|
|
426
|
+
) {
|
|
272
427
|
this.#actor = actor;
|
|
428
|
+
this.#storage = new WorkflowStorage(runtimeSqlFromContext(runCtx));
|
|
273
429
|
}
|
|
274
430
|
|
|
275
431
|
async get(key: Uint8Array): Promise<Uint8Array | null> {
|
|
276
|
-
|
|
277
|
-
makeWorkflowKey(key),
|
|
278
|
-
]);
|
|
279
|
-
return value ?? null;
|
|
432
|
+
return await this.#storage.get(key);
|
|
280
433
|
}
|
|
281
434
|
|
|
282
435
|
async set(key: Uint8Array, value: Uint8Array): Promise<void> {
|
|
283
|
-
await this.#
|
|
284
|
-
[makeWorkflowKey(key), value],
|
|
285
|
-
]);
|
|
436
|
+
await this.#storage.set(key, value);
|
|
286
437
|
}
|
|
287
438
|
|
|
288
439
|
async delete(key: Uint8Array): Promise<void> {
|
|
289
|
-
await this.#
|
|
290
|
-
makeWorkflowKey(key),
|
|
291
|
-
]);
|
|
440
|
+
await this.#storage.delete(key);
|
|
292
441
|
}
|
|
293
442
|
|
|
294
443
|
async deletePrefix(prefix: Uint8Array): Promise<void> {
|
|
295
|
-
|
|
296
|
-
const end = computeUpperBound(start);
|
|
297
|
-
if (end) {
|
|
298
|
-
await this.#actor.driver.kvDeleteRange(this.#actor.id, start, end);
|
|
299
|
-
return;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
const entries = await this.#actor.driver.kvListPrefix(
|
|
303
|
-
this.#actor.id,
|
|
304
|
-
start,
|
|
305
|
-
);
|
|
306
|
-
if (entries.length === 0) {
|
|
307
|
-
return;
|
|
308
|
-
}
|
|
309
|
-
await this.#actor.driver.kvBatchDelete(
|
|
310
|
-
this.#actor.id,
|
|
311
|
-
entries.map(([key]: KVEntryTuple) => key),
|
|
312
|
-
);
|
|
444
|
+
await this.#storage.deletePrefix(prefix);
|
|
313
445
|
}
|
|
314
446
|
|
|
315
447
|
async deleteRange(start: Uint8Array, end: Uint8Array): Promise<void> {
|
|
316
|
-
await this.#
|
|
317
|
-
this.#actor.id,
|
|
318
|
-
makeWorkflowKey(start),
|
|
319
|
-
makeWorkflowKey(end),
|
|
320
|
-
);
|
|
448
|
+
await this.#storage.deleteRange(start, end);
|
|
321
449
|
}
|
|
322
450
|
|
|
323
451
|
async list(prefix: Uint8Array): Promise<KVEntry[]> {
|
|
324
|
-
|
|
325
|
-
this.#actor.id,
|
|
326
|
-
makeWorkflowKey(prefix),
|
|
327
|
-
);
|
|
328
|
-
return entries.map(([key, value]: KVEntryTuple) => ({
|
|
329
|
-
key: stripWorkflowKey(key),
|
|
330
|
-
value,
|
|
331
|
-
}));
|
|
452
|
+
return await this.#storage.list(prefix);
|
|
332
453
|
}
|
|
333
454
|
|
|
334
455
|
async batch(writes: KVWrite[]): Promise<void> {
|
|
@@ -336,10 +457,7 @@ export class ActorWorkflowControlDriver implements EngineDriver {
|
|
|
336
457
|
return;
|
|
337
458
|
}
|
|
338
459
|
|
|
339
|
-
await this.#
|
|
340
|
-
this.#actor.id,
|
|
341
|
-
writes.map(({ key, value }) => [makeWorkflowKey(key), value]),
|
|
342
|
-
);
|
|
460
|
+
await this.#storage.batch(writes);
|
|
343
461
|
}
|
|
344
462
|
|
|
345
463
|
async setAlarm(_workflowId: string, wakeAt: number): Promise<void> {
|
package/src/workflow/mod.ts
CHANGED
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
RaceError,
|
|
7
7
|
RollbackCheckpointError,
|
|
8
8
|
RollbackError,
|
|
9
|
-
replayWorkflowFromStep,
|
|
10
9
|
type RunWorkflowOptions,
|
|
10
|
+
replayWorkflowFromStep,
|
|
11
11
|
runWorkflow,
|
|
12
12
|
StepExhaustedError,
|
|
13
13
|
type WorkflowErrorEvent,
|
|
@@ -201,7 +201,7 @@ export function workflow<
|
|
|
201
201
|
const workflowInspector = getWorkflowInspector(actor.id);
|
|
202
202
|
|
|
203
203
|
const driver = new ActorWorkflowDriver(actor, runCtx);
|
|
204
|
-
const controlDriver = new ActorWorkflowControlDriver(actor);
|
|
204
|
+
const controlDriver = new ActorWorkflowControlDriver(actor, runCtx);
|
|
205
205
|
workflowInspector.setReplayFromStep(async (entryId) => {
|
|
206
206
|
const workflowState = await workflowInspector.adapter.getState();
|
|
207
207
|
if (
|
|
@@ -212,7 +212,7 @@ export function workflow<
|
|
|
212
212
|
throw workflowReplayInFlightError();
|
|
213
213
|
}
|
|
214
214
|
|
|
215
|
-
let snapshot
|
|
215
|
+
let snapshot: Awaited<ReturnType<typeof replayWorkflowFromStep>>;
|
|
216
216
|
try {
|
|
217
217
|
snapshot = await replayWorkflowFromStep(
|
|
218
218
|
actor.id,
|