@rivetkit/workflow-engine 2.1.7 → 2.1.9
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/tsup/{chunk-MMWB37UG.js → chunk-4ME2JBMC.js} +110 -18
- package/dist/tsup/chunk-4ME2JBMC.js.map +1 -0
- package/dist/tsup/{chunk-SHICGAKC.cjs → chunk-OYYWSC77.cjs} +110 -18
- package/dist/tsup/chunk-OYYWSC77.cjs.map +1 -0
- package/dist/tsup/index.cjs +4 -2
- package/dist/tsup/index.cjs.map +1 -1
- package/dist/tsup/index.d.cts +9 -1
- package/dist/tsup/index.d.ts +9 -1
- package/dist/tsup/index.js +3 -1
- package/dist/tsup/testing.cjs +25 -23
- package/dist/tsup/testing.cjs.map +1 -1
- package/dist/tsup/testing.d.cts +1 -1
- package/dist/tsup/testing.d.ts +1 -1
- package/dist/tsup/testing.js +3 -1
- package/dist/tsup/testing.js.map +1 -1
- package/package.json +1 -1
- package/src/context.ts +11 -19
- package/src/index.ts +138 -8
- package/src/storage.ts +13 -1
- package/dist/tsup/chunk-MMWB37UG.js.map +0 -1
- package/dist/tsup/chunk-SHICGAKC.cjs.map +0 -1
package/dist/tsup/testing.cjs
CHANGED
|
@@ -46,7 +46,8 @@
|
|
|
46
46
|
|
|
47
47
|
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
|
|
50
|
+
var _chunkOYYWSC77cjs = require('./chunk-OYYWSC77.cjs');
|
|
50
51
|
|
|
51
52
|
// src/testing.ts
|
|
52
53
|
var InMemoryWorkflowMessageDriver = class {
|
|
@@ -96,7 +97,7 @@ var InMemoryWorkflowMessageDriver = class {
|
|
|
96
97
|
}
|
|
97
98
|
async waitForMessages(messageNames, abortSignal) {
|
|
98
99
|
if (abortSignal.aborted) {
|
|
99
|
-
throw new (0,
|
|
100
|
+
throw new (0, _chunkOYYWSC77cjs.EvictedError)();
|
|
100
101
|
}
|
|
101
102
|
const nameSet = messageNames.length > 0 ? new Set(messageNames) : void 0;
|
|
102
103
|
if (this.#messages.some(
|
|
@@ -117,7 +118,7 @@ var InMemoryWorkflowMessageDriver = class {
|
|
|
117
118
|
},
|
|
118
119
|
abortSignal,
|
|
119
120
|
onAbort: () => {
|
|
120
|
-
waiter.reject(new (0,
|
|
121
|
+
waiter.reject(new (0, _chunkOYYWSC77cjs.EvictedError)());
|
|
121
122
|
}
|
|
122
123
|
};
|
|
123
124
|
abortSignal.addEventListener("abort", waiter.onAbort, {
|
|
@@ -157,56 +158,56 @@ var InMemoryDriver = (_class = class {constructor() { _class.prototype.__init.ca
|
|
|
157
158
|
__init4() {this.workerPollInterval = 100}
|
|
158
159
|
__init5() {this.messageDriver = this.#inMemoryMessageDriver}
|
|
159
160
|
async get(key) {
|
|
160
|
-
await
|
|
161
|
-
const entry = this.kv.get(
|
|
161
|
+
await _chunkOYYWSC77cjs.sleep.call(void 0, this.latency);
|
|
162
|
+
const entry = this.kv.get(_chunkOYYWSC77cjs.keyToHex.call(void 0, key));
|
|
162
163
|
return _nullishCoalesce((entry == null ? void 0 : entry.value), () => ( null));
|
|
163
164
|
}
|
|
164
165
|
async set(key, value) {
|
|
165
|
-
await
|
|
166
|
-
this.kv.set(
|
|
166
|
+
await _chunkOYYWSC77cjs.sleep.call(void 0, this.latency);
|
|
167
|
+
this.kv.set(_chunkOYYWSC77cjs.keyToHex.call(void 0, key), { key, value });
|
|
167
168
|
}
|
|
168
169
|
async delete(key) {
|
|
169
|
-
await
|
|
170
|
-
this.kv.delete(
|
|
170
|
+
await _chunkOYYWSC77cjs.sleep.call(void 0, this.latency);
|
|
171
|
+
this.kv.delete(_chunkOYYWSC77cjs.keyToHex.call(void 0, key));
|
|
171
172
|
}
|
|
172
173
|
async deletePrefix(prefix) {
|
|
173
|
-
await
|
|
174
|
+
await _chunkOYYWSC77cjs.sleep.call(void 0, this.latency);
|
|
174
175
|
for (const [hexKey, entry] of this.kv) {
|
|
175
|
-
if (
|
|
176
|
+
if (_chunkOYYWSC77cjs.keyStartsWith.call(void 0, entry.key, prefix)) {
|
|
176
177
|
this.kv.delete(hexKey);
|
|
177
178
|
}
|
|
178
179
|
}
|
|
179
180
|
}
|
|
180
181
|
async deleteRange(start, end) {
|
|
181
|
-
await
|
|
182
|
+
await _chunkOYYWSC77cjs.sleep.call(void 0, this.latency);
|
|
182
183
|
for (const [hexKey, entry] of this.kv) {
|
|
183
|
-
if (
|
|
184
|
+
if (_chunkOYYWSC77cjs.compareKeys.call(void 0, entry.key, start) >= 0 && _chunkOYYWSC77cjs.compareKeys.call(void 0, entry.key, end) < 0) {
|
|
184
185
|
this.kv.delete(hexKey);
|
|
185
186
|
}
|
|
186
187
|
}
|
|
187
188
|
}
|
|
188
189
|
async list(prefix) {
|
|
189
|
-
await
|
|
190
|
+
await _chunkOYYWSC77cjs.sleep.call(void 0, this.latency);
|
|
190
191
|
const results = [];
|
|
191
192
|
for (const entry of this.kv.values()) {
|
|
192
|
-
if (
|
|
193
|
+
if (_chunkOYYWSC77cjs.keyStartsWith.call(void 0, entry.key, prefix)) {
|
|
193
194
|
results.push({ key: entry.key, value: entry.value });
|
|
194
195
|
}
|
|
195
196
|
}
|
|
196
|
-
return results.sort((a, b) =>
|
|
197
|
+
return results.sort((a, b) => _chunkOYYWSC77cjs.compareKeys.call(void 0, a.key, b.key));
|
|
197
198
|
}
|
|
198
199
|
async batch(writes) {
|
|
199
|
-
await
|
|
200
|
+
await _chunkOYYWSC77cjs.sleep.call(void 0, this.latency);
|
|
200
201
|
for (const { key, value } of writes) {
|
|
201
|
-
this.kv.set(
|
|
202
|
+
this.kv.set(_chunkOYYWSC77cjs.keyToHex.call(void 0, key), { key, value });
|
|
202
203
|
}
|
|
203
204
|
}
|
|
204
205
|
async setAlarm(workflowId, wakeAt) {
|
|
205
|
-
await
|
|
206
|
+
await _chunkOYYWSC77cjs.sleep.call(void 0, this.latency);
|
|
206
207
|
this.alarms.set(workflowId, wakeAt);
|
|
207
208
|
}
|
|
208
209
|
async clearAlarm(workflowId) {
|
|
209
|
-
await
|
|
210
|
+
await _chunkOYYWSC77cjs.sleep.call(void 0, this.latency);
|
|
210
211
|
this.alarms.delete(workflowId);
|
|
211
212
|
}
|
|
212
213
|
async waitForMessages(messageNames, abortSignal) {
|
|
@@ -217,7 +218,7 @@ var InMemoryDriver = (_class = class {constructor() { _class.prototype.__init.ca
|
|
|
217
218
|
}
|
|
218
219
|
while (true) {
|
|
219
220
|
if (abortSignal.aborted) {
|
|
220
|
-
throw new (0,
|
|
221
|
+
throw new (0, _chunkOYYWSC77cjs.EvictedError)();
|
|
221
222
|
}
|
|
222
223
|
const messages = await this.messageDriver.receiveMessages({
|
|
223
224
|
names: messageNames.length > 0 ? messageNames : void 0,
|
|
@@ -227,7 +228,7 @@ var InMemoryDriver = (_class = class {constructor() { _class.prototype.__init.ca
|
|
|
227
228
|
if (messages.length > 0) {
|
|
228
229
|
return;
|
|
229
230
|
}
|
|
230
|
-
await
|
|
231
|
+
await _chunkOYYWSC77cjs.sleep.call(void 0, Math.max(1, this.latency));
|
|
231
232
|
}
|
|
232
233
|
}
|
|
233
234
|
/**
|
|
@@ -322,5 +323,6 @@ var InMemoryDriver = (_class = class {constructor() { _class.prototype.__init.ca
|
|
|
322
323
|
|
|
323
324
|
|
|
324
325
|
|
|
325
|
-
|
|
326
|
+
|
|
327
|
+
exports.CancelledError = _chunkOYYWSC77cjs.CancelledError; exports.CriticalError = _chunkOYYWSC77cjs.CriticalError; exports.DEFAULT_LOOP_HISTORY_PRUNE_INTERVAL = _chunkOYYWSC77cjs.DEFAULT_LOOP_HISTORY_PRUNE_INTERVAL; exports.DEFAULT_MAX_RETRIES = _chunkOYYWSC77cjs.DEFAULT_MAX_RETRIES; exports.DEFAULT_RETRY_BACKOFF_BASE = _chunkOYYWSC77cjs.DEFAULT_RETRY_BACKOFF_BASE; exports.DEFAULT_RETRY_BACKOFF_MAX = _chunkOYYWSC77cjs.DEFAULT_RETRY_BACKOFF_MAX; exports.DEFAULT_STEP_TIMEOUT = _chunkOYYWSC77cjs.DEFAULT_STEP_TIMEOUT; exports.EntryInProgressError = _chunkOYYWSC77cjs.EntryInProgressError; exports.EvictedError = _chunkOYYWSC77cjs.EvictedError; exports.HistoryDivergedError = _chunkOYYWSC77cjs.HistoryDivergedError; exports.InMemoryDriver = InMemoryDriver; exports.JoinError = _chunkOYYWSC77cjs.JoinError; exports.Loop = _chunkOYYWSC77cjs.Loop; exports.MessageWaitError = _chunkOYYWSC77cjs.MessageWaitError; exports.RaceError = _chunkOYYWSC77cjs.RaceError; exports.RollbackCheckpointError = _chunkOYYWSC77cjs.RollbackCheckpointError; exports.RollbackError = _chunkOYYWSC77cjs.RollbackError; exports.SleepError = _chunkOYYWSC77cjs.SleepError; exports.StepExhaustedError = _chunkOYYWSC77cjs.StepExhaustedError; exports.StepFailedError = _chunkOYYWSC77cjs.StepFailedError; exports.WorkflowContextImpl = _chunkOYYWSC77cjs.WorkflowContextImpl; exports.appendLoopIteration = _chunkOYYWSC77cjs.appendLoopIteration; exports.appendName = _chunkOYYWSC77cjs.appendName; exports.createEntry = _chunkOYYWSC77cjs.createEntry; exports.createHistorySnapshot = _chunkOYYWSC77cjs.createHistorySnapshot; exports.createStorage = _chunkOYYWSC77cjs.createStorage; exports.deleteEntriesWithPrefix = _chunkOYYWSC77cjs.deleteEntriesWithPrefix; exports.emptyLocation = _chunkOYYWSC77cjs.emptyLocation; exports.extractErrorInfo = _chunkOYYWSC77cjs.extractErrorInfo; exports.flush = _chunkOYYWSC77cjs.flush; exports.generateId = _chunkOYYWSC77cjs.generateId; exports.getEntry = _chunkOYYWSC77cjs.getEntry; exports.getOrCreateMetadata = _chunkOYYWSC77cjs.getOrCreateMetadata; exports.isLocationPrefix = _chunkOYYWSC77cjs.isLocationPrefix; exports.isLoopIterationMarker = _chunkOYYWSC77cjs.isLoopIterationMarker; exports.loadMetadata = _chunkOYYWSC77cjs.loadMetadata; exports.loadStorage = _chunkOYYWSC77cjs.loadStorage; exports.locationToKey = _chunkOYYWSC77cjs.locationToKey; exports.locationsEqual = _chunkOYYWSC77cjs.locationsEqual; exports.parentLocation = _chunkOYYWSC77cjs.parentLocation; exports.registerName = _chunkOYYWSC77cjs.registerName; exports.replayWorkflowFromStep = _chunkOYYWSC77cjs.replayWorkflowFromStep; exports.resolveName = _chunkOYYWSC77cjs.resolveName; exports.runWorkflow = _chunkOYYWSC77cjs.runWorkflow; exports.setEntry = _chunkOYYWSC77cjs.setEntry;
|
|
326
328
|
//# sourceMappingURL=testing.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/runner/work/rivet/rivet/rivetkit-typescript/packages/workflow-engine/dist/tsup/testing.cjs","../../src/testing.ts"],"names":[],"mappings":"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","file":"/home/runner/work/rivet/rivet/rivetkit-typescript/packages/workflow-engine/dist/tsup/testing.cjs","sourcesContent":[null,"import type { EngineDriver, KVEntry, KVWrite } from \"./driver.js\";\nimport { EvictedError } from \"./errors.js\";\nimport { compareKeys, keyStartsWith, keyToHex } from \"./keys.js\";\nimport type { Message, WorkflowMessageDriver } from \"./types.js\";\nimport { sleep } from \"./utils.js\";\n\ninterface Waiter {\n\tnameSet?: Set<string>;\n\tresolve: () => void;\n\treject: (error: Error) => void;\n\tabortSignal: AbortSignal;\n\tonAbort: () => void;\n}\n\nclass InMemoryWorkflowMessageDriver implements WorkflowMessageDriver {\n\t#messages: Message[] = [];\n\t#waiters = new Set<Waiter>();\n\n\tasync addMessage(message: Message): Promise<void> {\n\t\tthis.#messages.push(message);\n\t\tthis.#notifyWaiters(message.name);\n\t}\n\n\tasync receiveMessages(opts: {\n\t\tnames?: readonly string[];\n\t\tcount: number;\n\t\tcompletable: boolean;\n\t}): Promise<Message[]> {\n\t\tconst limitedCount = Math.max(1, opts.count);\n\t\tconst nameSet =\n\t\t\topts.names && opts.names.length > 0\n\t\t\t\t? new Set(opts.names)\n\t\t\t\t: undefined;\n\t\tconst selected: Array<{ message: Message; index: number }> = [];\n\n\t\tfor (\n\t\t\tlet i = 0;\n\t\t\ti < this.#messages.length && selected.length < limitedCount;\n\t\t\ti++\n\t\t) {\n\t\t\tconst message = this.#messages[i];\n\t\t\tif (nameSet && !nameSet.has(message.name)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tselected.push({ message, index: i });\n\t\t}\n\n\t\tif (selected.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tif (!opts.completable) {\n\t\t\tfor (let i = selected.length - 1; i >= 0; i--) {\n\t\t\t\tthis.#messages.splice(selected[i].index, 1);\n\t\t\t}\n\t\t\treturn selected.map((entry) => entry.message);\n\t\t}\n\n\t\treturn selected.map((entry) => {\n\t\t\tconst { message } = entry;\n\t\t\treturn {\n\t\t\t\t...message,\n\t\t\t\tcomplete: async () => {\n\t\t\t\t\tawait this.completeMessage(message.id);\n\t\t\t\t},\n\t\t\t};\n\t\t});\n\t}\n\n\tasync completeMessage(messageId: string): Promise<void> {\n\t\tconst index = this.#messages.findIndex(\n\t\t\t(message) => message.id === messageId,\n\t\t);\n\t\tif (index !== -1) {\n\t\t\tthis.#messages.splice(index, 1);\n\t\t}\n\t}\n\n\tasync waitForMessages(\n\t\tmessageNames: string[],\n\t\tabortSignal: AbortSignal,\n\t): Promise<void> {\n\t\tif (abortSignal.aborted) {\n\t\t\tthrow new EvictedError();\n\t\t}\n\n\t\tconst nameSet =\n\t\t\tmessageNames.length > 0 ? new Set(messageNames) : undefined;\n\t\tif (\n\t\t\tthis.#messages.some((message) =>\n\t\t\t\tnameSet ? nameSet.has(message.name) : true,\n\t\t\t)\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\tconst waiter: Waiter = {\n\t\t\t\tnameSet,\n\t\t\t\tresolve: () => {\n\t\t\t\t\tthis.#removeWaiter(waiter);\n\t\t\t\t\tresolve();\n\t\t\t\t},\n\t\t\t\treject: (error) => {\n\t\t\t\t\tthis.#removeWaiter(waiter);\n\t\t\t\t\treject(error);\n\t\t\t\t},\n\t\t\t\tabortSignal,\n\t\t\t\tonAbort: () => {\n\t\t\t\t\twaiter.reject(new EvictedError());\n\t\t\t\t},\n\t\t\t};\n\t\t\tabortSignal.addEventListener(\"abort\", waiter.onAbort, {\n\t\t\t\tonce: true,\n\t\t\t});\n\t\t\tthis.#waiters.add(waiter);\n\t\t});\n\t}\n\n\t#removeWaiter(waiter: Waiter): void {\n\t\tif (this.#waiters.delete(waiter)) {\n\t\t\twaiter.abortSignal.removeEventListener(\"abort\", waiter.onAbort);\n\t\t}\n\t}\n\n\t#notifyWaiters(name: string): void {\n\t\tfor (const waiter of [...this.#waiters]) {\n\t\t\tif (waiter.nameSet && !waiter.nameSet.has(name)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\twaiter.resolve();\n\t\t}\n\t}\n\n\tclear(): void {\n\t\tthis.#messages = [];\n\t\tfor (const waiter of [...this.#waiters]) {\n\t\t\twaiter.reject(new Error(\"cleared\"));\n\t\t}\n\t}\n}\n\n/**\n * In-memory implementation of EngineDriver for testing.\n * Uses binary keys (Uint8Array) with hex encoding for internal Map storage.\n */\nexport class InMemoryDriver implements EngineDriver {\n\t// Map from hex-encoded key to { originalKey, value }\n\tprivate kv = new Map<string, { key: Uint8Array; value: Uint8Array }>();\n\tprivate alarms = new Map<string, number>();\n\t#inMemoryMessageDriver = new InMemoryWorkflowMessageDriver();\n\n\t/** Simulated latency per operation (ms) */\n\tlatency = 10;\n\n\t/** How often the worker polls for work */\n\tworkerPollInterval = 100;\n\tmessageDriver: WorkflowMessageDriver = this.#inMemoryMessageDriver;\n\n\tasync get(key: Uint8Array): Promise<Uint8Array | null> {\n\t\tawait sleep(this.latency);\n\t\tconst entry = this.kv.get(keyToHex(key));\n\t\treturn entry?.value ?? null;\n\t}\n\n\tasync set(key: Uint8Array, value: Uint8Array): Promise<void> {\n\t\tawait sleep(this.latency);\n\t\tthis.kv.set(keyToHex(key), { key, value });\n\t}\n\n\tasync delete(key: Uint8Array): Promise<void> {\n\t\tawait sleep(this.latency);\n\t\tthis.kv.delete(keyToHex(key));\n\t}\n\n\tasync deletePrefix(prefix: Uint8Array): Promise<void> {\n\t\tawait sleep(this.latency);\n\t\tfor (const [hexKey, entry] of this.kv) {\n\t\t\tif (keyStartsWith(entry.key, prefix)) {\n\t\t\t\tthis.kv.delete(hexKey);\n\t\t\t}\n\t\t}\n\t}\n\n\tasync deleteRange(start: Uint8Array, end: Uint8Array): Promise<void> {\n\t\tawait sleep(this.latency);\n\t\tfor (const [hexKey, entry] of this.kv) {\n\t\t\tif (\n\t\t\t\tcompareKeys(entry.key, start) >= 0 &&\n\t\t\t\tcompareKeys(entry.key, end) < 0\n\t\t\t) {\n\t\t\t\tthis.kv.delete(hexKey);\n\t\t\t}\n\t\t}\n\t}\n\n\tasync list(prefix: Uint8Array): Promise<KVEntry[]> {\n\t\tawait sleep(this.latency);\n\t\tconst results: KVEntry[] = [];\n\t\tfor (const entry of this.kv.values()) {\n\t\t\tif (keyStartsWith(entry.key, prefix)) {\n\t\t\t\tresults.push({ key: entry.key, value: entry.value });\n\t\t\t}\n\t\t}\n\t\t// Sort by key lexicographically\n\t\treturn results.sort((a, b) => compareKeys(a.key, b.key));\n\t}\n\n\tasync batch(writes: KVWrite[]): Promise<void> {\n\t\tawait sleep(this.latency);\n\t\tfor (const { key, value } of writes) {\n\t\t\tthis.kv.set(keyToHex(key), { key, value });\n\t\t}\n\t}\n\n\tasync setAlarm(workflowId: string, wakeAt: number): Promise<void> {\n\t\tawait sleep(this.latency);\n\t\tthis.alarms.set(workflowId, wakeAt);\n\t}\n\n\tasync clearAlarm(workflowId: string): Promise<void> {\n\t\tawait sleep(this.latency);\n\t\tthis.alarms.delete(workflowId);\n\t}\n\n\tasync waitForMessages(\n\t\tmessageNames: string[],\n\t\tabortSignal: AbortSignal,\n\t): Promise<void> {\n\t\tconst driver = this.messageDriver as WorkflowMessageDriver & {\n\t\t\twaitForMessages?: (\n\t\t\t\tmessageNames: string[],\n\t\t\t\tabortSignal: AbortSignal,\n\t\t\t) => Promise<void>;\n\t\t};\n\t\tif (driver.waitForMessages) {\n\t\t\tawait driver.waitForMessages(messageNames, abortSignal);\n\t\t\treturn;\n\t\t}\n\n\t\twhile (true) {\n\t\t\tif (abortSignal.aborted) {\n\t\t\t\tthrow new EvictedError();\n\t\t\t}\n\t\t\tconst messages = await this.messageDriver.receiveMessages({\n\t\t\t\tnames: messageNames.length > 0 ? messageNames : undefined,\n\t\t\t\tcount: 1,\n\t\t\t\tcompletable: true,\n\t\t\t});\n\t\t\tif (messages.length > 0) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait sleep(Math.max(1, this.latency));\n\t\t}\n\t}\n\n\t/**\n\t * Get the alarm time for a workflow (for testing).\n\t */\n\tgetAlarm(workflowId: string): number | undefined {\n\t\treturn this.alarms.get(workflowId);\n\t}\n\n\t/**\n\t * Check if any alarms are due and return their workflow IDs.\n\t */\n\tgetDueAlarms(): string[] {\n\t\tconst now = Date.now();\n\t\tconst due: string[] = [];\n\t\tfor (const [workflowId, wakeAt] of this.alarms) {\n\t\t\tif (wakeAt <= now) {\n\t\t\t\tdue.push(workflowId);\n\t\t\t}\n\t\t}\n\t\treturn due;\n\t}\n\n\t/**\n\t * Clear all data (for testing).\n\t */\n\tclear(): void {\n\t\tthis.kv.clear();\n\t\tthis.alarms.clear();\n\t\tthis.#inMemoryMessageDriver.clear();\n\t}\n\n\t/**\n\t * Get a snapshot of all data (for testing/debugging).\n\t */\n\tsnapshot(): {\n\t\tkv: Record<string, Uint8Array>;\n\t\talarms: Record<string, number>;\n\t} {\n\t\tconst kvSnapshot: Record<string, Uint8Array> = {};\n\t\tfor (const [hexKey, entry] of this.kv) {\n\t\t\tkvSnapshot[hexKey] = entry.value;\n\t\t}\n\t\treturn {\n\t\t\tkv: kvSnapshot,\n\t\t\talarms: Object.fromEntries(this.alarms),\n\t\t};\n\t}\n\n\t/**\n\t * Get all hex-encoded keys (for testing).\n\t */\n\tkeys(): string[] {\n\t\treturn [...this.kv.keys()];\n\t}\n}\n\n// Re-export main exports for convenience\nexport * from \"./index.js\";\n"]}
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/rivet/rivet/rivetkit-typescript/packages/workflow-engine/dist/tsup/testing.cjs","../../src/testing.ts"],"names":[],"mappings":"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","file":"/home/runner/work/rivet/rivet/rivetkit-typescript/packages/workflow-engine/dist/tsup/testing.cjs","sourcesContent":[null,"import type { EngineDriver, KVEntry, KVWrite } from \"./driver.js\";\nimport { EvictedError } from \"./errors.js\";\nimport { compareKeys, keyStartsWith, keyToHex } from \"./keys.js\";\nimport type { Message, WorkflowMessageDriver } from \"./types.js\";\nimport { sleep } from \"./utils.js\";\n\ninterface Waiter {\n\tnameSet?: Set<string>;\n\tresolve: () => void;\n\treject: (error: Error) => void;\n\tabortSignal: AbortSignal;\n\tonAbort: () => void;\n}\n\nclass InMemoryWorkflowMessageDriver implements WorkflowMessageDriver {\n\t#messages: Message[] = [];\n\t#waiters = new Set<Waiter>();\n\n\tasync addMessage(message: Message): Promise<void> {\n\t\tthis.#messages.push(message);\n\t\tthis.#notifyWaiters(message.name);\n\t}\n\n\tasync receiveMessages(opts: {\n\t\tnames?: readonly string[];\n\t\tcount: number;\n\t\tcompletable: boolean;\n\t}): Promise<Message[]> {\n\t\tconst limitedCount = Math.max(1, opts.count);\n\t\tconst nameSet =\n\t\t\topts.names && opts.names.length > 0\n\t\t\t\t? new Set(opts.names)\n\t\t\t\t: undefined;\n\t\tconst selected: Array<{ message: Message; index: number }> = [];\n\n\t\tfor (\n\t\t\tlet i = 0;\n\t\t\ti < this.#messages.length && selected.length < limitedCount;\n\t\t\ti++\n\t\t) {\n\t\t\tconst message = this.#messages[i];\n\t\t\tif (nameSet && !nameSet.has(message.name)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tselected.push({ message, index: i });\n\t\t}\n\n\t\tif (selected.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tif (!opts.completable) {\n\t\t\tfor (let i = selected.length - 1; i >= 0; i--) {\n\t\t\t\tthis.#messages.splice(selected[i].index, 1);\n\t\t\t}\n\t\t\treturn selected.map((entry) => entry.message);\n\t\t}\n\n\t\treturn selected.map((entry) => {\n\t\t\tconst { message } = entry;\n\t\t\treturn {\n\t\t\t\t...message,\n\t\t\t\tcomplete: async () => {\n\t\t\t\t\tawait this.completeMessage(message.id);\n\t\t\t\t},\n\t\t\t};\n\t\t});\n\t}\n\n\tasync completeMessage(messageId: string): Promise<void> {\n\t\tconst index = this.#messages.findIndex(\n\t\t\t(message) => message.id === messageId,\n\t\t);\n\t\tif (index !== -1) {\n\t\t\tthis.#messages.splice(index, 1);\n\t\t}\n\t}\n\n\tasync waitForMessages(\n\t\tmessageNames: string[],\n\t\tabortSignal: AbortSignal,\n\t): Promise<void> {\n\t\tif (abortSignal.aborted) {\n\t\t\tthrow new EvictedError();\n\t\t}\n\n\t\tconst nameSet =\n\t\t\tmessageNames.length > 0 ? new Set(messageNames) : undefined;\n\t\tif (\n\t\t\tthis.#messages.some((message) =>\n\t\t\t\tnameSet ? nameSet.has(message.name) : true,\n\t\t\t)\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\tconst waiter: Waiter = {\n\t\t\t\tnameSet,\n\t\t\t\tresolve: () => {\n\t\t\t\t\tthis.#removeWaiter(waiter);\n\t\t\t\t\tresolve();\n\t\t\t\t},\n\t\t\t\treject: (error) => {\n\t\t\t\t\tthis.#removeWaiter(waiter);\n\t\t\t\t\treject(error);\n\t\t\t\t},\n\t\t\t\tabortSignal,\n\t\t\t\tonAbort: () => {\n\t\t\t\t\twaiter.reject(new EvictedError());\n\t\t\t\t},\n\t\t\t};\n\t\t\tabortSignal.addEventListener(\"abort\", waiter.onAbort, {\n\t\t\t\tonce: true,\n\t\t\t});\n\t\t\tthis.#waiters.add(waiter);\n\t\t});\n\t}\n\n\t#removeWaiter(waiter: Waiter): void {\n\t\tif (this.#waiters.delete(waiter)) {\n\t\t\twaiter.abortSignal.removeEventListener(\"abort\", waiter.onAbort);\n\t\t}\n\t}\n\n\t#notifyWaiters(name: string): void {\n\t\tfor (const waiter of [...this.#waiters]) {\n\t\t\tif (waiter.nameSet && !waiter.nameSet.has(name)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\twaiter.resolve();\n\t\t}\n\t}\n\n\tclear(): void {\n\t\tthis.#messages = [];\n\t\tfor (const waiter of [...this.#waiters]) {\n\t\t\twaiter.reject(new Error(\"cleared\"));\n\t\t}\n\t}\n}\n\n/**\n * In-memory implementation of EngineDriver for testing.\n * Uses binary keys (Uint8Array) with hex encoding for internal Map storage.\n */\nexport class InMemoryDriver implements EngineDriver {\n\t// Map from hex-encoded key to { originalKey, value }\n\tprivate kv = new Map<string, { key: Uint8Array; value: Uint8Array }>();\n\tprivate alarms = new Map<string, number>();\n\t#inMemoryMessageDriver = new InMemoryWorkflowMessageDriver();\n\n\t/** Simulated latency per operation (ms) */\n\tlatency = 10;\n\n\t/** How often the worker polls for work */\n\tworkerPollInterval = 100;\n\tmessageDriver: WorkflowMessageDriver = this.#inMemoryMessageDriver;\n\n\tasync get(key: Uint8Array): Promise<Uint8Array | null> {\n\t\tawait sleep(this.latency);\n\t\tconst entry = this.kv.get(keyToHex(key));\n\t\treturn entry?.value ?? null;\n\t}\n\n\tasync set(key: Uint8Array, value: Uint8Array): Promise<void> {\n\t\tawait sleep(this.latency);\n\t\tthis.kv.set(keyToHex(key), { key, value });\n\t}\n\n\tasync delete(key: Uint8Array): Promise<void> {\n\t\tawait sleep(this.latency);\n\t\tthis.kv.delete(keyToHex(key));\n\t}\n\n\tasync deletePrefix(prefix: Uint8Array): Promise<void> {\n\t\tawait sleep(this.latency);\n\t\tfor (const [hexKey, entry] of this.kv) {\n\t\t\tif (keyStartsWith(entry.key, prefix)) {\n\t\t\t\tthis.kv.delete(hexKey);\n\t\t\t}\n\t\t}\n\t}\n\n\tasync deleteRange(start: Uint8Array, end: Uint8Array): Promise<void> {\n\t\tawait sleep(this.latency);\n\t\tfor (const [hexKey, entry] of this.kv) {\n\t\t\tif (\n\t\t\t\tcompareKeys(entry.key, start) >= 0 &&\n\t\t\t\tcompareKeys(entry.key, end) < 0\n\t\t\t) {\n\t\t\t\tthis.kv.delete(hexKey);\n\t\t\t}\n\t\t}\n\t}\n\n\tasync list(prefix: Uint8Array): Promise<KVEntry[]> {\n\t\tawait sleep(this.latency);\n\t\tconst results: KVEntry[] = [];\n\t\tfor (const entry of this.kv.values()) {\n\t\t\tif (keyStartsWith(entry.key, prefix)) {\n\t\t\t\tresults.push({ key: entry.key, value: entry.value });\n\t\t\t}\n\t\t}\n\t\t// Sort by key lexicographically\n\t\treturn results.sort((a, b) => compareKeys(a.key, b.key));\n\t}\n\n\tasync batch(writes: KVWrite[]): Promise<void> {\n\t\tawait sleep(this.latency);\n\t\tfor (const { key, value } of writes) {\n\t\t\tthis.kv.set(keyToHex(key), { key, value });\n\t\t}\n\t}\n\n\tasync setAlarm(workflowId: string, wakeAt: number): Promise<void> {\n\t\tawait sleep(this.latency);\n\t\tthis.alarms.set(workflowId, wakeAt);\n\t}\n\n\tasync clearAlarm(workflowId: string): Promise<void> {\n\t\tawait sleep(this.latency);\n\t\tthis.alarms.delete(workflowId);\n\t}\n\n\tasync waitForMessages(\n\t\tmessageNames: string[],\n\t\tabortSignal: AbortSignal,\n\t): Promise<void> {\n\t\tconst driver = this.messageDriver as WorkflowMessageDriver & {\n\t\t\twaitForMessages?: (\n\t\t\t\tmessageNames: string[],\n\t\t\t\tabortSignal: AbortSignal,\n\t\t\t) => Promise<void>;\n\t\t};\n\t\tif (driver.waitForMessages) {\n\t\t\tawait driver.waitForMessages(messageNames, abortSignal);\n\t\t\treturn;\n\t\t}\n\n\t\twhile (true) {\n\t\t\tif (abortSignal.aborted) {\n\t\t\t\tthrow new EvictedError();\n\t\t\t}\n\t\t\tconst messages = await this.messageDriver.receiveMessages({\n\t\t\t\tnames: messageNames.length > 0 ? messageNames : undefined,\n\t\t\t\tcount: 1,\n\t\t\t\tcompletable: true,\n\t\t\t});\n\t\t\tif (messages.length > 0) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait sleep(Math.max(1, this.latency));\n\t\t}\n\t}\n\n\t/**\n\t * Get the alarm time for a workflow (for testing).\n\t */\n\tgetAlarm(workflowId: string): number | undefined {\n\t\treturn this.alarms.get(workflowId);\n\t}\n\n\t/**\n\t * Check if any alarms are due and return their workflow IDs.\n\t */\n\tgetDueAlarms(): string[] {\n\t\tconst now = Date.now();\n\t\tconst due: string[] = [];\n\t\tfor (const [workflowId, wakeAt] of this.alarms) {\n\t\t\tif (wakeAt <= now) {\n\t\t\t\tdue.push(workflowId);\n\t\t\t}\n\t\t}\n\t\treturn due;\n\t}\n\n\t/**\n\t * Clear all data (for testing).\n\t */\n\tclear(): void {\n\t\tthis.kv.clear();\n\t\tthis.alarms.clear();\n\t\tthis.#inMemoryMessageDriver.clear();\n\t}\n\n\t/**\n\t * Get a snapshot of all data (for testing/debugging).\n\t */\n\tsnapshot(): {\n\t\tkv: Record<string, Uint8Array>;\n\t\talarms: Record<string, number>;\n\t} {\n\t\tconst kvSnapshot: Record<string, Uint8Array> = {};\n\t\tfor (const [hexKey, entry] of this.kv) {\n\t\t\tkvSnapshot[hexKey] = entry.value;\n\t\t}\n\t\treturn {\n\t\t\tkv: kvSnapshot,\n\t\t\talarms: Object.fromEntries(this.alarms),\n\t\t};\n\t}\n\n\t/**\n\t * Get all hex-encoded keys (for testing).\n\t */\n\tkeys(): string[] {\n\t\treturn [...this.kv.keys()];\n\t}\n}\n\n// Re-export main exports for convenience\nexport * from \"./index.js\";\n"]}
|
package/dist/tsup/testing.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { EngineDriver, WorkflowMessageDriver, KVEntry, KVWrite } from './index.cjs';
|
|
2
|
-
export { BranchConfig, BranchOutput, BranchStatus, BranchStatusType, CancelledError, CriticalError, DEFAULT_LOOP_HISTORY_PRUNE_INTERVAL, DEFAULT_MAX_RETRIES, DEFAULT_RETRY_BACKOFF_BASE, DEFAULT_RETRY_BACKOFF_MAX, DEFAULT_STEP_TIMEOUT, Entry, EntryInProgressError, EntryKind, EntryKindType, EntryMetadata, EntryStatus, EvictedError, History, HistoryDivergedError, JoinEntry, JoinError, Location, Loop, LoopConfig, LoopEntry, LoopIterationMarker, LoopResult, Message, MessageEntry, MessageWaitError, NameIndex, PathSegment, RaceEntry, RaceError, RemovedEntry, RollbackCheckpointEntry, RollbackCheckpointError, RollbackContextInterface, RollbackError, RunWorkflowOptions, SleepEntry, SleepError, SleepState, StepConfig, StepEntry, StepExhaustedError, StepFailedError, Storage, WorkflowContextImpl, WorkflowContextInterface, WorkflowEntryMetadataSnapshot, WorkflowError, WorkflowErrorEvent, WorkflowErrorHandler, WorkflowFunction, WorkflowHandle, WorkflowHistoryEntry, WorkflowHistorySnapshot, WorkflowQueue, WorkflowQueueMessage, WorkflowQueueNextBatchOptions, WorkflowQueueNextOptions, WorkflowResult, WorkflowRollbackErrorEvent, WorkflowRunErrorEvent, WorkflowRunMode, WorkflowState, WorkflowStepErrorEvent, appendLoopIteration, appendName, createEntry, createHistorySnapshot, createStorage, deleteEntriesWithPrefix, emptyLocation, extractErrorInfo, flush, generateId, getEntry, getOrCreateMetadata, isLocationPrefix, isLoopIterationMarker, loadMetadata, loadStorage, locationToKey, locationsEqual, parentLocation, registerName, resolveName, runWorkflow, setEntry } from './index.cjs';
|
|
2
|
+
export { BranchConfig, BranchOutput, BranchStatus, BranchStatusType, CancelledError, CriticalError, DEFAULT_LOOP_HISTORY_PRUNE_INTERVAL, DEFAULT_MAX_RETRIES, DEFAULT_RETRY_BACKOFF_BASE, DEFAULT_RETRY_BACKOFF_MAX, DEFAULT_STEP_TIMEOUT, Entry, EntryInProgressError, EntryKind, EntryKindType, EntryMetadata, EntryStatus, EvictedError, History, HistoryDivergedError, JoinEntry, JoinError, Location, Loop, LoopConfig, LoopEntry, LoopIterationMarker, LoopResult, Message, MessageEntry, MessageWaitError, NameIndex, PathSegment, RaceEntry, RaceError, RemovedEntry, RollbackCheckpointEntry, RollbackCheckpointError, RollbackContextInterface, RollbackError, RunWorkflowOptions, SleepEntry, SleepError, SleepState, StepConfig, StepEntry, StepExhaustedError, StepFailedError, Storage, WorkflowContextImpl, WorkflowContextInterface, WorkflowEntryMetadataSnapshot, WorkflowError, WorkflowErrorEvent, WorkflowErrorHandler, WorkflowFunction, WorkflowHandle, WorkflowHistoryEntry, WorkflowHistorySnapshot, WorkflowQueue, WorkflowQueueMessage, WorkflowQueueNextBatchOptions, WorkflowQueueNextOptions, WorkflowResult, WorkflowRollbackErrorEvent, WorkflowRunErrorEvent, WorkflowRunMode, WorkflowState, WorkflowStepErrorEvent, appendLoopIteration, appendName, createEntry, createHistorySnapshot, createStorage, deleteEntriesWithPrefix, emptyLocation, extractErrorInfo, flush, generateId, getEntry, getOrCreateMetadata, isLocationPrefix, isLoopIterationMarker, loadMetadata, loadStorage, locationToKey, locationsEqual, parentLocation, registerName, replayWorkflowFromStep, resolveName, runWorkflow, setEntry } from './index.cjs';
|
|
3
3
|
import 'pino';
|
|
4
4
|
|
|
5
5
|
/**
|
package/dist/tsup/testing.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { EngineDriver, WorkflowMessageDriver, KVEntry, KVWrite } from './index.js';
|
|
2
|
-
export { BranchConfig, BranchOutput, BranchStatus, BranchStatusType, CancelledError, CriticalError, DEFAULT_LOOP_HISTORY_PRUNE_INTERVAL, DEFAULT_MAX_RETRIES, DEFAULT_RETRY_BACKOFF_BASE, DEFAULT_RETRY_BACKOFF_MAX, DEFAULT_STEP_TIMEOUT, Entry, EntryInProgressError, EntryKind, EntryKindType, EntryMetadata, EntryStatus, EvictedError, History, HistoryDivergedError, JoinEntry, JoinError, Location, Loop, LoopConfig, LoopEntry, LoopIterationMarker, LoopResult, Message, MessageEntry, MessageWaitError, NameIndex, PathSegment, RaceEntry, RaceError, RemovedEntry, RollbackCheckpointEntry, RollbackCheckpointError, RollbackContextInterface, RollbackError, RunWorkflowOptions, SleepEntry, SleepError, SleepState, StepConfig, StepEntry, StepExhaustedError, StepFailedError, Storage, WorkflowContextImpl, WorkflowContextInterface, WorkflowEntryMetadataSnapshot, WorkflowError, WorkflowErrorEvent, WorkflowErrorHandler, WorkflowFunction, WorkflowHandle, WorkflowHistoryEntry, WorkflowHistorySnapshot, WorkflowQueue, WorkflowQueueMessage, WorkflowQueueNextBatchOptions, WorkflowQueueNextOptions, WorkflowResult, WorkflowRollbackErrorEvent, WorkflowRunErrorEvent, WorkflowRunMode, WorkflowState, WorkflowStepErrorEvent, appendLoopIteration, appendName, createEntry, createHistorySnapshot, createStorage, deleteEntriesWithPrefix, emptyLocation, extractErrorInfo, flush, generateId, getEntry, getOrCreateMetadata, isLocationPrefix, isLoopIterationMarker, loadMetadata, loadStorage, locationToKey, locationsEqual, parentLocation, registerName, resolveName, runWorkflow, setEntry } from './index.js';
|
|
2
|
+
export { BranchConfig, BranchOutput, BranchStatus, BranchStatusType, CancelledError, CriticalError, DEFAULT_LOOP_HISTORY_PRUNE_INTERVAL, DEFAULT_MAX_RETRIES, DEFAULT_RETRY_BACKOFF_BASE, DEFAULT_RETRY_BACKOFF_MAX, DEFAULT_STEP_TIMEOUT, Entry, EntryInProgressError, EntryKind, EntryKindType, EntryMetadata, EntryStatus, EvictedError, History, HistoryDivergedError, JoinEntry, JoinError, Location, Loop, LoopConfig, LoopEntry, LoopIterationMarker, LoopResult, Message, MessageEntry, MessageWaitError, NameIndex, PathSegment, RaceEntry, RaceError, RemovedEntry, RollbackCheckpointEntry, RollbackCheckpointError, RollbackContextInterface, RollbackError, RunWorkflowOptions, SleepEntry, SleepError, SleepState, StepConfig, StepEntry, StepExhaustedError, StepFailedError, Storage, WorkflowContextImpl, WorkflowContextInterface, WorkflowEntryMetadataSnapshot, WorkflowError, WorkflowErrorEvent, WorkflowErrorHandler, WorkflowFunction, WorkflowHandle, WorkflowHistoryEntry, WorkflowHistorySnapshot, WorkflowQueue, WorkflowQueueMessage, WorkflowQueueNextBatchOptions, WorkflowQueueNextOptions, WorkflowResult, WorkflowRollbackErrorEvent, WorkflowRunErrorEvent, WorkflowRunMode, WorkflowState, WorkflowStepErrorEvent, appendLoopIteration, appendName, createEntry, createHistorySnapshot, createStorage, deleteEntriesWithPrefix, emptyLocation, extractErrorInfo, flush, generateId, getEntry, getOrCreateMetadata, isLocationPrefix, isLoopIterationMarker, loadMetadata, loadStorage, locationToKey, locationsEqual, parentLocation, registerName, replayWorkflowFromStep, resolveName, runWorkflow, setEntry } from './index.js';
|
|
3
3
|
import 'pino';
|
|
4
4
|
|
|
5
5
|
/**
|
package/dist/tsup/testing.js
CHANGED
|
@@ -42,11 +42,12 @@ import {
|
|
|
42
42
|
locationsEqual,
|
|
43
43
|
parentLocation,
|
|
44
44
|
registerName,
|
|
45
|
+
replayWorkflowFromStep,
|
|
45
46
|
resolveName,
|
|
46
47
|
runWorkflow,
|
|
47
48
|
setEntry,
|
|
48
49
|
sleep
|
|
49
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-4ME2JBMC.js";
|
|
50
51
|
|
|
51
52
|
// src/testing.ts
|
|
52
53
|
var InMemoryWorkflowMessageDriver = class {
|
|
@@ -319,6 +320,7 @@ export {
|
|
|
319
320
|
locationsEqual,
|
|
320
321
|
parentLocation,
|
|
321
322
|
registerName,
|
|
323
|
+
replayWorkflowFromStep,
|
|
322
324
|
resolveName,
|
|
323
325
|
runWorkflow,
|
|
324
326
|
setEntry
|
package/dist/tsup/testing.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/testing.ts"],"sourcesContent":["import type { EngineDriver, KVEntry, KVWrite } from \"./driver.js\";\nimport { EvictedError } from \"./errors.js\";\nimport { compareKeys, keyStartsWith, keyToHex } from \"./keys.js\";\nimport type { Message, WorkflowMessageDriver } from \"./types.js\";\nimport { sleep } from \"./utils.js\";\n\ninterface Waiter {\n\tnameSet?: Set<string>;\n\tresolve: () => void;\n\treject: (error: Error) => void;\n\tabortSignal: AbortSignal;\n\tonAbort: () => void;\n}\n\nclass InMemoryWorkflowMessageDriver implements WorkflowMessageDriver {\n\t#messages: Message[] = [];\n\t#waiters = new Set<Waiter>();\n\n\tasync addMessage(message: Message): Promise<void> {\n\t\tthis.#messages.push(message);\n\t\tthis.#notifyWaiters(message.name);\n\t}\n\n\tasync receiveMessages(opts: {\n\t\tnames?: readonly string[];\n\t\tcount: number;\n\t\tcompletable: boolean;\n\t}): Promise<Message[]> {\n\t\tconst limitedCount = Math.max(1, opts.count);\n\t\tconst nameSet =\n\t\t\topts.names && opts.names.length > 0\n\t\t\t\t? new Set(opts.names)\n\t\t\t\t: undefined;\n\t\tconst selected: Array<{ message: Message; index: number }> = [];\n\n\t\tfor (\n\t\t\tlet i = 0;\n\t\t\ti < this.#messages.length && selected.length < limitedCount;\n\t\t\ti++\n\t\t) {\n\t\t\tconst message = this.#messages[i];\n\t\t\tif (nameSet && !nameSet.has(message.name)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tselected.push({ message, index: i });\n\t\t}\n\n\t\tif (selected.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tif (!opts.completable) {\n\t\t\tfor (let i = selected.length - 1; i >= 0; i--) {\n\t\t\t\tthis.#messages.splice(selected[i].index, 1);\n\t\t\t}\n\t\t\treturn selected.map((entry) => entry.message);\n\t\t}\n\n\t\treturn selected.map((entry) => {\n\t\t\tconst { message } = entry;\n\t\t\treturn {\n\t\t\t\t...message,\n\t\t\t\tcomplete: async () => {\n\t\t\t\t\tawait this.completeMessage(message.id);\n\t\t\t\t},\n\t\t\t};\n\t\t});\n\t}\n\n\tasync completeMessage(messageId: string): Promise<void> {\n\t\tconst index = this.#messages.findIndex(\n\t\t\t(message) => message.id === messageId,\n\t\t);\n\t\tif (index !== -1) {\n\t\t\tthis.#messages.splice(index, 1);\n\t\t}\n\t}\n\n\tasync waitForMessages(\n\t\tmessageNames: string[],\n\t\tabortSignal: AbortSignal,\n\t): Promise<void> {\n\t\tif (abortSignal.aborted) {\n\t\t\tthrow new EvictedError();\n\t\t}\n\n\t\tconst nameSet =\n\t\t\tmessageNames.length > 0 ? new Set(messageNames) : undefined;\n\t\tif (\n\t\t\tthis.#messages.some((message) =>\n\t\t\t\tnameSet ? nameSet.has(message.name) : true,\n\t\t\t)\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\tconst waiter: Waiter = {\n\t\t\t\tnameSet,\n\t\t\t\tresolve: () => {\n\t\t\t\t\tthis.#removeWaiter(waiter);\n\t\t\t\t\tresolve();\n\t\t\t\t},\n\t\t\t\treject: (error) => {\n\t\t\t\t\tthis.#removeWaiter(waiter);\n\t\t\t\t\treject(error);\n\t\t\t\t},\n\t\t\t\tabortSignal,\n\t\t\t\tonAbort: () => {\n\t\t\t\t\twaiter.reject(new EvictedError());\n\t\t\t\t},\n\t\t\t};\n\t\t\tabortSignal.addEventListener(\"abort\", waiter.onAbort, {\n\t\t\t\tonce: true,\n\t\t\t});\n\t\t\tthis.#waiters.add(waiter);\n\t\t});\n\t}\n\n\t#removeWaiter(waiter: Waiter): void {\n\t\tif (this.#waiters.delete(waiter)) {\n\t\t\twaiter.abortSignal.removeEventListener(\"abort\", waiter.onAbort);\n\t\t}\n\t}\n\n\t#notifyWaiters(name: string): void {\n\t\tfor (const waiter of [...this.#waiters]) {\n\t\t\tif (waiter.nameSet && !waiter.nameSet.has(name)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\twaiter.resolve();\n\t\t}\n\t}\n\n\tclear(): void {\n\t\tthis.#messages = [];\n\t\tfor (const waiter of [...this.#waiters]) {\n\t\t\twaiter.reject(new Error(\"cleared\"));\n\t\t}\n\t}\n}\n\n/**\n * In-memory implementation of EngineDriver for testing.\n * Uses binary keys (Uint8Array) with hex encoding for internal Map storage.\n */\nexport class InMemoryDriver implements EngineDriver {\n\t// Map from hex-encoded key to { originalKey, value }\n\tprivate kv = new Map<string, { key: Uint8Array; value: Uint8Array }>();\n\tprivate alarms = new Map<string, number>();\n\t#inMemoryMessageDriver = new InMemoryWorkflowMessageDriver();\n\n\t/** Simulated latency per operation (ms) */\n\tlatency = 10;\n\n\t/** How often the worker polls for work */\n\tworkerPollInterval = 100;\n\tmessageDriver: WorkflowMessageDriver = this.#inMemoryMessageDriver;\n\n\tasync get(key: Uint8Array): Promise<Uint8Array | null> {\n\t\tawait sleep(this.latency);\n\t\tconst entry = this.kv.get(keyToHex(key));\n\t\treturn entry?.value ?? null;\n\t}\n\n\tasync set(key: Uint8Array, value: Uint8Array): Promise<void> {\n\t\tawait sleep(this.latency);\n\t\tthis.kv.set(keyToHex(key), { key, value });\n\t}\n\n\tasync delete(key: Uint8Array): Promise<void> {\n\t\tawait sleep(this.latency);\n\t\tthis.kv.delete(keyToHex(key));\n\t}\n\n\tasync deletePrefix(prefix: Uint8Array): Promise<void> {\n\t\tawait sleep(this.latency);\n\t\tfor (const [hexKey, entry] of this.kv) {\n\t\t\tif (keyStartsWith(entry.key, prefix)) {\n\t\t\t\tthis.kv.delete(hexKey);\n\t\t\t}\n\t\t}\n\t}\n\n\tasync deleteRange(start: Uint8Array, end: Uint8Array): Promise<void> {\n\t\tawait sleep(this.latency);\n\t\tfor (const [hexKey, entry] of this.kv) {\n\t\t\tif (\n\t\t\t\tcompareKeys(entry.key, start) >= 0 &&\n\t\t\t\tcompareKeys(entry.key, end) < 0\n\t\t\t) {\n\t\t\t\tthis.kv.delete(hexKey);\n\t\t\t}\n\t\t}\n\t}\n\n\tasync list(prefix: Uint8Array): Promise<KVEntry[]> {\n\t\tawait sleep(this.latency);\n\t\tconst results: KVEntry[] = [];\n\t\tfor (const entry of this.kv.values()) {\n\t\t\tif (keyStartsWith(entry.key, prefix)) {\n\t\t\t\tresults.push({ key: entry.key, value: entry.value });\n\t\t\t}\n\t\t}\n\t\t// Sort by key lexicographically\n\t\treturn results.sort((a, b) => compareKeys(a.key, b.key));\n\t}\n\n\tasync batch(writes: KVWrite[]): Promise<void> {\n\t\tawait sleep(this.latency);\n\t\tfor (const { key, value } of writes) {\n\t\t\tthis.kv.set(keyToHex(key), { key, value });\n\t\t}\n\t}\n\n\tasync setAlarm(workflowId: string, wakeAt: number): Promise<void> {\n\t\tawait sleep(this.latency);\n\t\tthis.alarms.set(workflowId, wakeAt);\n\t}\n\n\tasync clearAlarm(workflowId: string): Promise<void> {\n\t\tawait sleep(this.latency);\n\t\tthis.alarms.delete(workflowId);\n\t}\n\n\tasync waitForMessages(\n\t\tmessageNames: string[],\n\t\tabortSignal: AbortSignal,\n\t): Promise<void> {\n\t\tconst driver = this.messageDriver as WorkflowMessageDriver & {\n\t\t\twaitForMessages?: (\n\t\t\t\tmessageNames: string[],\n\t\t\t\tabortSignal: AbortSignal,\n\t\t\t) => Promise<void>;\n\t\t};\n\t\tif (driver.waitForMessages) {\n\t\t\tawait driver.waitForMessages(messageNames, abortSignal);\n\t\t\treturn;\n\t\t}\n\n\t\twhile (true) {\n\t\t\tif (abortSignal.aborted) {\n\t\t\t\tthrow new EvictedError();\n\t\t\t}\n\t\t\tconst messages = await this.messageDriver.receiveMessages({\n\t\t\t\tnames: messageNames.length > 0 ? messageNames : undefined,\n\t\t\t\tcount: 1,\n\t\t\t\tcompletable: true,\n\t\t\t});\n\t\t\tif (messages.length > 0) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait sleep(Math.max(1, this.latency));\n\t\t}\n\t}\n\n\t/**\n\t * Get the alarm time for a workflow (for testing).\n\t */\n\tgetAlarm(workflowId: string): number | undefined {\n\t\treturn this.alarms.get(workflowId);\n\t}\n\n\t/**\n\t * Check if any alarms are due and return their workflow IDs.\n\t */\n\tgetDueAlarms(): string[] {\n\t\tconst now = Date.now();\n\t\tconst due: string[] = [];\n\t\tfor (const [workflowId, wakeAt] of this.alarms) {\n\t\t\tif (wakeAt <= now) {\n\t\t\t\tdue.push(workflowId);\n\t\t\t}\n\t\t}\n\t\treturn due;\n\t}\n\n\t/**\n\t * Clear all data (for testing).\n\t */\n\tclear(): void {\n\t\tthis.kv.clear();\n\t\tthis.alarms.clear();\n\t\tthis.#inMemoryMessageDriver.clear();\n\t}\n\n\t/**\n\t * Get a snapshot of all data (for testing/debugging).\n\t */\n\tsnapshot(): {\n\t\tkv: Record<string, Uint8Array>;\n\t\talarms: Record<string, number>;\n\t} {\n\t\tconst kvSnapshot: Record<string, Uint8Array> = {};\n\t\tfor (const [hexKey, entry] of this.kv) {\n\t\t\tkvSnapshot[hexKey] = entry.value;\n\t\t}\n\t\treturn {\n\t\t\tkv: kvSnapshot,\n\t\t\talarms: Object.fromEntries(this.alarms),\n\t\t};\n\t}\n\n\t/**\n\t * Get all hex-encoded keys (for testing).\n\t */\n\tkeys(): string[] {\n\t\treturn [...this.kv.keys()];\n\t}\n}\n\n// Re-export main exports for convenience\nexport * from \"./index.js\";\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/testing.ts"],"sourcesContent":["import type { EngineDriver, KVEntry, KVWrite } from \"./driver.js\";\nimport { EvictedError } from \"./errors.js\";\nimport { compareKeys, keyStartsWith, keyToHex } from \"./keys.js\";\nimport type { Message, WorkflowMessageDriver } from \"./types.js\";\nimport { sleep } from \"./utils.js\";\n\ninterface Waiter {\n\tnameSet?: Set<string>;\n\tresolve: () => void;\n\treject: (error: Error) => void;\n\tabortSignal: AbortSignal;\n\tonAbort: () => void;\n}\n\nclass InMemoryWorkflowMessageDriver implements WorkflowMessageDriver {\n\t#messages: Message[] = [];\n\t#waiters = new Set<Waiter>();\n\n\tasync addMessage(message: Message): Promise<void> {\n\t\tthis.#messages.push(message);\n\t\tthis.#notifyWaiters(message.name);\n\t}\n\n\tasync receiveMessages(opts: {\n\t\tnames?: readonly string[];\n\t\tcount: number;\n\t\tcompletable: boolean;\n\t}): Promise<Message[]> {\n\t\tconst limitedCount = Math.max(1, opts.count);\n\t\tconst nameSet =\n\t\t\topts.names && opts.names.length > 0\n\t\t\t\t? new Set(opts.names)\n\t\t\t\t: undefined;\n\t\tconst selected: Array<{ message: Message; index: number }> = [];\n\n\t\tfor (\n\t\t\tlet i = 0;\n\t\t\ti < this.#messages.length && selected.length < limitedCount;\n\t\t\ti++\n\t\t) {\n\t\t\tconst message = this.#messages[i];\n\t\t\tif (nameSet && !nameSet.has(message.name)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tselected.push({ message, index: i });\n\t\t}\n\n\t\tif (selected.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tif (!opts.completable) {\n\t\t\tfor (let i = selected.length - 1; i >= 0; i--) {\n\t\t\t\tthis.#messages.splice(selected[i].index, 1);\n\t\t\t}\n\t\t\treturn selected.map((entry) => entry.message);\n\t\t}\n\n\t\treturn selected.map((entry) => {\n\t\t\tconst { message } = entry;\n\t\t\treturn {\n\t\t\t\t...message,\n\t\t\t\tcomplete: async () => {\n\t\t\t\t\tawait this.completeMessage(message.id);\n\t\t\t\t},\n\t\t\t};\n\t\t});\n\t}\n\n\tasync completeMessage(messageId: string): Promise<void> {\n\t\tconst index = this.#messages.findIndex(\n\t\t\t(message) => message.id === messageId,\n\t\t);\n\t\tif (index !== -1) {\n\t\t\tthis.#messages.splice(index, 1);\n\t\t}\n\t}\n\n\tasync waitForMessages(\n\t\tmessageNames: string[],\n\t\tabortSignal: AbortSignal,\n\t): Promise<void> {\n\t\tif (abortSignal.aborted) {\n\t\t\tthrow new EvictedError();\n\t\t}\n\n\t\tconst nameSet =\n\t\t\tmessageNames.length > 0 ? new Set(messageNames) : undefined;\n\t\tif (\n\t\t\tthis.#messages.some((message) =>\n\t\t\t\tnameSet ? nameSet.has(message.name) : true,\n\t\t\t)\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\tconst waiter: Waiter = {\n\t\t\t\tnameSet,\n\t\t\t\tresolve: () => {\n\t\t\t\t\tthis.#removeWaiter(waiter);\n\t\t\t\t\tresolve();\n\t\t\t\t},\n\t\t\t\treject: (error) => {\n\t\t\t\t\tthis.#removeWaiter(waiter);\n\t\t\t\t\treject(error);\n\t\t\t\t},\n\t\t\t\tabortSignal,\n\t\t\t\tonAbort: () => {\n\t\t\t\t\twaiter.reject(new EvictedError());\n\t\t\t\t},\n\t\t\t};\n\t\t\tabortSignal.addEventListener(\"abort\", waiter.onAbort, {\n\t\t\t\tonce: true,\n\t\t\t});\n\t\t\tthis.#waiters.add(waiter);\n\t\t});\n\t}\n\n\t#removeWaiter(waiter: Waiter): void {\n\t\tif (this.#waiters.delete(waiter)) {\n\t\t\twaiter.abortSignal.removeEventListener(\"abort\", waiter.onAbort);\n\t\t}\n\t}\n\n\t#notifyWaiters(name: string): void {\n\t\tfor (const waiter of [...this.#waiters]) {\n\t\t\tif (waiter.nameSet && !waiter.nameSet.has(name)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\twaiter.resolve();\n\t\t}\n\t}\n\n\tclear(): void {\n\t\tthis.#messages = [];\n\t\tfor (const waiter of [...this.#waiters]) {\n\t\t\twaiter.reject(new Error(\"cleared\"));\n\t\t}\n\t}\n}\n\n/**\n * In-memory implementation of EngineDriver for testing.\n * Uses binary keys (Uint8Array) with hex encoding for internal Map storage.\n */\nexport class InMemoryDriver implements EngineDriver {\n\t// Map from hex-encoded key to { originalKey, value }\n\tprivate kv = new Map<string, { key: Uint8Array; value: Uint8Array }>();\n\tprivate alarms = new Map<string, number>();\n\t#inMemoryMessageDriver = new InMemoryWorkflowMessageDriver();\n\n\t/** Simulated latency per operation (ms) */\n\tlatency = 10;\n\n\t/** How often the worker polls for work */\n\tworkerPollInterval = 100;\n\tmessageDriver: WorkflowMessageDriver = this.#inMemoryMessageDriver;\n\n\tasync get(key: Uint8Array): Promise<Uint8Array | null> {\n\t\tawait sleep(this.latency);\n\t\tconst entry = this.kv.get(keyToHex(key));\n\t\treturn entry?.value ?? null;\n\t}\n\n\tasync set(key: Uint8Array, value: Uint8Array): Promise<void> {\n\t\tawait sleep(this.latency);\n\t\tthis.kv.set(keyToHex(key), { key, value });\n\t}\n\n\tasync delete(key: Uint8Array): Promise<void> {\n\t\tawait sleep(this.latency);\n\t\tthis.kv.delete(keyToHex(key));\n\t}\n\n\tasync deletePrefix(prefix: Uint8Array): Promise<void> {\n\t\tawait sleep(this.latency);\n\t\tfor (const [hexKey, entry] of this.kv) {\n\t\t\tif (keyStartsWith(entry.key, prefix)) {\n\t\t\t\tthis.kv.delete(hexKey);\n\t\t\t}\n\t\t}\n\t}\n\n\tasync deleteRange(start: Uint8Array, end: Uint8Array): Promise<void> {\n\t\tawait sleep(this.latency);\n\t\tfor (const [hexKey, entry] of this.kv) {\n\t\t\tif (\n\t\t\t\tcompareKeys(entry.key, start) >= 0 &&\n\t\t\t\tcompareKeys(entry.key, end) < 0\n\t\t\t) {\n\t\t\t\tthis.kv.delete(hexKey);\n\t\t\t}\n\t\t}\n\t}\n\n\tasync list(prefix: Uint8Array): Promise<KVEntry[]> {\n\t\tawait sleep(this.latency);\n\t\tconst results: KVEntry[] = [];\n\t\tfor (const entry of this.kv.values()) {\n\t\t\tif (keyStartsWith(entry.key, prefix)) {\n\t\t\t\tresults.push({ key: entry.key, value: entry.value });\n\t\t\t}\n\t\t}\n\t\t// Sort by key lexicographically\n\t\treturn results.sort((a, b) => compareKeys(a.key, b.key));\n\t}\n\n\tasync batch(writes: KVWrite[]): Promise<void> {\n\t\tawait sleep(this.latency);\n\t\tfor (const { key, value } of writes) {\n\t\t\tthis.kv.set(keyToHex(key), { key, value });\n\t\t}\n\t}\n\n\tasync setAlarm(workflowId: string, wakeAt: number): Promise<void> {\n\t\tawait sleep(this.latency);\n\t\tthis.alarms.set(workflowId, wakeAt);\n\t}\n\n\tasync clearAlarm(workflowId: string): Promise<void> {\n\t\tawait sleep(this.latency);\n\t\tthis.alarms.delete(workflowId);\n\t}\n\n\tasync waitForMessages(\n\t\tmessageNames: string[],\n\t\tabortSignal: AbortSignal,\n\t): Promise<void> {\n\t\tconst driver = this.messageDriver as WorkflowMessageDriver & {\n\t\t\twaitForMessages?: (\n\t\t\t\tmessageNames: string[],\n\t\t\t\tabortSignal: AbortSignal,\n\t\t\t) => Promise<void>;\n\t\t};\n\t\tif (driver.waitForMessages) {\n\t\t\tawait driver.waitForMessages(messageNames, abortSignal);\n\t\t\treturn;\n\t\t}\n\n\t\twhile (true) {\n\t\t\tif (abortSignal.aborted) {\n\t\t\t\tthrow new EvictedError();\n\t\t\t}\n\t\t\tconst messages = await this.messageDriver.receiveMessages({\n\t\t\t\tnames: messageNames.length > 0 ? messageNames : undefined,\n\t\t\t\tcount: 1,\n\t\t\t\tcompletable: true,\n\t\t\t});\n\t\t\tif (messages.length > 0) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait sleep(Math.max(1, this.latency));\n\t\t}\n\t}\n\n\t/**\n\t * Get the alarm time for a workflow (for testing).\n\t */\n\tgetAlarm(workflowId: string): number | undefined {\n\t\treturn this.alarms.get(workflowId);\n\t}\n\n\t/**\n\t * Check if any alarms are due and return their workflow IDs.\n\t */\n\tgetDueAlarms(): string[] {\n\t\tconst now = Date.now();\n\t\tconst due: string[] = [];\n\t\tfor (const [workflowId, wakeAt] of this.alarms) {\n\t\t\tif (wakeAt <= now) {\n\t\t\t\tdue.push(workflowId);\n\t\t\t}\n\t\t}\n\t\treturn due;\n\t}\n\n\t/**\n\t * Clear all data (for testing).\n\t */\n\tclear(): void {\n\t\tthis.kv.clear();\n\t\tthis.alarms.clear();\n\t\tthis.#inMemoryMessageDriver.clear();\n\t}\n\n\t/**\n\t * Get a snapshot of all data (for testing/debugging).\n\t */\n\tsnapshot(): {\n\t\tkv: Record<string, Uint8Array>;\n\t\talarms: Record<string, number>;\n\t} {\n\t\tconst kvSnapshot: Record<string, Uint8Array> = {};\n\t\tfor (const [hexKey, entry] of this.kv) {\n\t\t\tkvSnapshot[hexKey] = entry.value;\n\t\t}\n\t\treturn {\n\t\t\tkv: kvSnapshot,\n\t\t\talarms: Object.fromEntries(this.alarms),\n\t\t};\n\t}\n\n\t/**\n\t * Get all hex-encoded keys (for testing).\n\t */\n\tkeys(): string[] {\n\t\treturn [...this.kv.keys()];\n\t}\n}\n\n// Re-export main exports for convenience\nexport * from \"./index.js\";\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
package/src/context.ts
CHANGED
|
@@ -280,7 +280,7 @@ export class WorkflowContextImpl implements WorkflowContextInterface {
|
|
|
280
280
|
if (this.usedNamesInExecution.has(fullKey)) {
|
|
281
281
|
throw new HistoryDivergedError(
|
|
282
282
|
`Duplicate entry name "${name}" at location "${locationToKey(this.storage, this.currentLocation)}". ` +
|
|
283
|
-
|
|
283
|
+
`Each step/loop/sleep/queue.next/join/race must have a unique name within its scope.`,
|
|
284
284
|
);
|
|
285
285
|
}
|
|
286
286
|
this.usedNamesInExecution.add(fullKey);
|
|
@@ -358,7 +358,7 @@ export class WorkflowContextImpl implements WorkflowContextInterface {
|
|
|
358
358
|
// This means workflow code may have changed
|
|
359
359
|
throw new HistoryDivergedError(
|
|
360
360
|
`Entry "${key}" exists in history but was not visited. ` +
|
|
361
|
-
|
|
361
|
+
`Workflow code may have changed. Use ctx.removed() to handle migrations.`,
|
|
362
362
|
);
|
|
363
363
|
}
|
|
364
364
|
}
|
|
@@ -617,16 +617,11 @@ export class WorkflowContextImpl implements WorkflowContextInterface {
|
|
|
617
617
|
retryBackoffMax,
|
|
618
618
|
);
|
|
619
619
|
const retryAt = metadata.lastAttemptAt + retryDelay;
|
|
620
|
-
await this.notifyStepError(
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
willRetry: true,
|
|
626
|
-
retryDelay,
|
|
627
|
-
retryAt,
|
|
628
|
-
},
|
|
629
|
-
);
|
|
620
|
+
await this.notifyStepError(config, metadata.attempts, error, {
|
|
621
|
+
willRetry: true,
|
|
622
|
+
retryDelay,
|
|
623
|
+
retryAt,
|
|
624
|
+
});
|
|
630
625
|
throw new StepFailedError(
|
|
631
626
|
config.name,
|
|
632
627
|
error,
|
|
@@ -638,12 +633,9 @@ export class WorkflowContextImpl implements WorkflowContextInterface {
|
|
|
638
633
|
const exhaustedError = markErrorReported(
|
|
639
634
|
new StepExhaustedError(config.name, String(error)),
|
|
640
635
|
);
|
|
641
|
-
await this.notifyStepError(
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
error,
|
|
645
|
-
{ willRetry: false },
|
|
646
|
-
);
|
|
636
|
+
await this.notifyStepError(config, metadata.attempts, error, {
|
|
637
|
+
willRetry: false,
|
|
638
|
+
});
|
|
647
639
|
throw exhaustedError;
|
|
648
640
|
}
|
|
649
641
|
}
|
|
@@ -1557,7 +1549,7 @@ export class WorkflowContextImpl implements WorkflowContextInterface {
|
|
|
1557
1549
|
typeof value === "object" &&
|
|
1558
1550
|
value !== null &&
|
|
1559
1551
|
(value as Record<string, unknown>)[QUEUE_HISTORY_MESSAGE_MARKER] ===
|
|
1560
|
-
|
|
1552
|
+
1
|
|
1561
1553
|
) {
|
|
1562
1554
|
const serialized = value as Record<string, unknown>;
|
|
1563
1555
|
const id = typeof serialized.id === "string" ? serialized.id : "";
|
package/src/index.ts
CHANGED
|
@@ -154,12 +154,15 @@ import {
|
|
|
154
154
|
StepFailedError,
|
|
155
155
|
} from "./errors.js";
|
|
156
156
|
import {
|
|
157
|
+
buildEntryMetadataKey,
|
|
157
158
|
buildEntryMetadataPrefix,
|
|
159
|
+
buildHistoryKey,
|
|
158
160
|
buildWorkflowErrorKey,
|
|
159
161
|
buildWorkflowInputKey,
|
|
160
162
|
buildWorkflowOutputKey,
|
|
161
163
|
buildWorkflowStateKey,
|
|
162
164
|
} from "./keys.js";
|
|
165
|
+
import { isLocationPrefix } from "./location.js";
|
|
163
166
|
import {
|
|
164
167
|
createHistorySnapshot,
|
|
165
168
|
flush,
|
|
@@ -168,6 +171,8 @@ import {
|
|
|
168
171
|
loadStorage,
|
|
169
172
|
} from "./storage.js";
|
|
170
173
|
import type {
|
|
174
|
+
Entry,
|
|
175
|
+
EntryMetadata,
|
|
171
176
|
RollbackContextInterface,
|
|
172
177
|
RunWorkflowOptions,
|
|
173
178
|
Storage,
|
|
@@ -199,6 +204,12 @@ interface LiveRuntime {
|
|
|
199
204
|
|
|
200
205
|
type HistoryNotifier = (() => void) | undefined;
|
|
201
206
|
|
|
207
|
+
type ReplayEntryRecord = {
|
|
208
|
+
key: string;
|
|
209
|
+
entry: Entry;
|
|
210
|
+
metadata: EntryMetadata;
|
|
211
|
+
};
|
|
212
|
+
|
|
202
213
|
function createLiveRuntime(): LiveRuntime {
|
|
203
214
|
return {
|
|
204
215
|
isSleeping: false,
|
|
@@ -331,14 +342,14 @@ async function executeRollback<TInput, TOutput>(
|
|
|
331
342
|
metadata.rollbackError =
|
|
332
343
|
error instanceof Error ? error.message : String(error);
|
|
333
344
|
if (onError) {
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
345
|
+
rollbackEvent = {
|
|
346
|
+
rollback: {
|
|
347
|
+
workflowId,
|
|
348
|
+
stepName: action.name,
|
|
349
|
+
error: extractErrorInfo(error),
|
|
350
|
+
},
|
|
351
|
+
};
|
|
352
|
+
}
|
|
342
353
|
if (error instanceof Error) {
|
|
343
354
|
markErrorReported(error);
|
|
344
355
|
}
|
|
@@ -728,6 +739,125 @@ export function runWorkflow<TInput, TOutput>(
|
|
|
728
739
|
};
|
|
729
740
|
}
|
|
730
741
|
|
|
742
|
+
/**
|
|
743
|
+
* Remove a step and every later workflow entry, then schedule the workflow to
|
|
744
|
+
* start again immediately. Omitting `entryId` replays the workflow from the
|
|
745
|
+
* beginning.
|
|
746
|
+
*/
|
|
747
|
+
export async function replayWorkflowFromStep(
|
|
748
|
+
workflowId: string,
|
|
749
|
+
driver: EngineDriver,
|
|
750
|
+
entryId?: string,
|
|
751
|
+
options?: {
|
|
752
|
+
scheduleAlarm?: boolean;
|
|
753
|
+
},
|
|
754
|
+
): Promise<WorkflowHistorySnapshot> {
|
|
755
|
+
const storage = await loadStorage(driver);
|
|
756
|
+
const entries = await Promise.all(
|
|
757
|
+
Array.from(storage.history.entries.entries()).map(
|
|
758
|
+
async ([key, entry]) => ({
|
|
759
|
+
key,
|
|
760
|
+
entry,
|
|
761
|
+
metadata: await loadMetadata(storage, driver, entry.id),
|
|
762
|
+
}),
|
|
763
|
+
),
|
|
764
|
+
);
|
|
765
|
+
const ordered = [...entries].sort((a, b) => {
|
|
766
|
+
if (a.metadata.createdAt !== b.metadata.createdAt) {
|
|
767
|
+
return a.metadata.createdAt - b.metadata.createdAt;
|
|
768
|
+
}
|
|
769
|
+
return a.key.localeCompare(b.key);
|
|
770
|
+
});
|
|
771
|
+
|
|
772
|
+
let entriesToDelete = ordered;
|
|
773
|
+
if (entryId !== undefined) {
|
|
774
|
+
const target = entries.find(({ entry }) => entry.id === entryId);
|
|
775
|
+
if (!target) {
|
|
776
|
+
throw new Error(`Workflow step not found: ${entryId}`);
|
|
777
|
+
}
|
|
778
|
+
if (target.entry.kind.type !== "step") {
|
|
779
|
+
throw new Error("Workflow replay target must be a step");
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
const replayBoundary = findReplayBoundaryEntry(entries, target);
|
|
783
|
+
const targetIndex = ordered.findIndex(
|
|
784
|
+
({ entry }) => entry.id === replayBoundary.entry.id,
|
|
785
|
+
);
|
|
786
|
+
entriesToDelete = ordered.slice(targetIndex);
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
const entryIdsToDelete = new Set(
|
|
790
|
+
entriesToDelete.map(({ entry }) => entry.id),
|
|
791
|
+
);
|
|
792
|
+
if (
|
|
793
|
+
entries.some(
|
|
794
|
+
({ entry, metadata }) =>
|
|
795
|
+
metadata.status === "running" &&
|
|
796
|
+
!entryIdsToDelete.has(entry.id),
|
|
797
|
+
)
|
|
798
|
+
) {
|
|
799
|
+
throw new Error(
|
|
800
|
+
"Cannot replay a workflow while a step is currently running",
|
|
801
|
+
);
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
await Promise.all(
|
|
805
|
+
entriesToDelete.flatMap(({ entry }) => [
|
|
806
|
+
driver.delete(buildHistoryKey(entry.location)),
|
|
807
|
+
driver.delete(buildEntryMetadataKey(entry.id)),
|
|
808
|
+
]),
|
|
809
|
+
);
|
|
810
|
+
|
|
811
|
+
for (const { key, entry } of entriesToDelete) {
|
|
812
|
+
storage.history.entries.delete(key);
|
|
813
|
+
storage.entryMetadata.delete(entry.id);
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
storage.output = undefined;
|
|
817
|
+
storage.flushedOutput = undefined;
|
|
818
|
+
storage.error = undefined;
|
|
819
|
+
storage.flushedError = undefined;
|
|
820
|
+
storage.state = "sleeping";
|
|
821
|
+
storage.flushedState = "sleeping";
|
|
822
|
+
|
|
823
|
+
await Promise.all([
|
|
824
|
+
driver.delete(buildWorkflowOutputKey()),
|
|
825
|
+
driver.delete(buildWorkflowErrorKey()),
|
|
826
|
+
driver.set(buildWorkflowStateKey(), serializeWorkflowState("sleeping")),
|
|
827
|
+
]);
|
|
828
|
+
if (options?.scheduleAlarm ?? true) {
|
|
829
|
+
await driver.setAlarm(workflowId, Date.now());
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
return createHistorySnapshot(storage);
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
function findReplayBoundaryEntry(
|
|
836
|
+
entries: ReplayEntryRecord[],
|
|
837
|
+
target: ReplayEntryRecord,
|
|
838
|
+
): ReplayEntryRecord {
|
|
839
|
+
let boundary = target;
|
|
840
|
+
let boundaryDepth = -1;
|
|
841
|
+
|
|
842
|
+
for (const candidate of entries) {
|
|
843
|
+
if (candidate.entry.kind.type !== "loop") {
|
|
844
|
+
continue;
|
|
845
|
+
}
|
|
846
|
+
if (
|
|
847
|
+
candidate.entry.location.length >= target.entry.location.length ||
|
|
848
|
+
!isLocationPrefix(candidate.entry.location, target.entry.location)
|
|
849
|
+
) {
|
|
850
|
+
continue;
|
|
851
|
+
}
|
|
852
|
+
if (candidate.entry.location.length > boundaryDepth) {
|
|
853
|
+
boundary = candidate;
|
|
854
|
+
boundaryDepth = candidate.entry.location.length;
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
return boundary;
|
|
859
|
+
}
|
|
860
|
+
|
|
731
861
|
/**
|
|
732
862
|
* Internal: Execute the workflow and return the result.
|
|
733
863
|
*/
|
package/src/storage.ts
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
import type { EngineDriver, KVWrite } from "./driver.js";
|
|
16
16
|
import {
|
|
17
17
|
buildEntryMetadataKey,
|
|
18
|
+
buildEntryMetadataPrefix,
|
|
18
19
|
buildHistoryKey,
|
|
19
20
|
buildHistoryPrefix,
|
|
20
21
|
buildHistoryPrefixAll,
|
|
@@ -24,6 +25,7 @@ import {
|
|
|
24
25
|
buildWorkflowOutputKey,
|
|
25
26
|
buildWorkflowStateKey,
|
|
26
27
|
compareKeys,
|
|
28
|
+
parseEntryMetadataKey,
|
|
27
29
|
parseNameKey,
|
|
28
30
|
} from "./keys.js";
|
|
29
31
|
import { isLocationPrefix, locationToKey } from "./location.js";
|
|
@@ -153,6 +155,16 @@ export async function loadStorage(driver: EngineDriver): Promise<Storage> {
|
|
|
153
155
|
storage.history.entries.set(key, parsed);
|
|
154
156
|
}
|
|
155
157
|
|
|
158
|
+
// Load entry metadata so observers can reconstruct workflow state after
|
|
159
|
+
// the actor wakes and rebuilds storage from persisted history.
|
|
160
|
+
const metadataEntries = await driver.list(buildEntryMetadataPrefix());
|
|
161
|
+
for (const entry of metadataEntries) {
|
|
162
|
+
const entryId = parseEntryMetadataKey(entry.key);
|
|
163
|
+
const metadata = deserializeEntryMetadata(entry.value);
|
|
164
|
+
metadata.dirty = false;
|
|
165
|
+
storage.entryMetadata.set(entryId, metadata);
|
|
166
|
+
}
|
|
167
|
+
|
|
156
168
|
// Load workflow state
|
|
157
169
|
const stateValue = await driver.get(buildWorkflowStateKey());
|
|
158
170
|
if (stateValue) {
|
|
@@ -402,4 +414,4 @@ export function setEntry(
|
|
|
402
414
|
): void {
|
|
403
415
|
const key = locationToKey(storage, location);
|
|
404
416
|
storage.history.entries.set(key, entry);
|
|
405
|
-
}
|
|
417
|
+
}
|