@rivetkit/workflow-engine 0.0.0-sqlite-profiling-compat.4a9a623 → 0.0.0-sqlite-sync-3-0-0-release.14341d0
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/schemas/v1.ts +25 -0
- package/dist/tsup/{chunk-KA2T56AJ.js → chunk-AAAPEYGX.js} +221 -44
- package/dist/tsup/chunk-AAAPEYGX.js.map +1 -0
- package/dist/tsup/{chunk-GQWOLYBA.cjs → chunk-XRITRTKT.cjs} +221 -44
- package/dist/tsup/chunk-XRITRTKT.cjs.map +1 -0
- package/dist/tsup/index.cjs +2 -2
- package/dist/tsup/index.cjs.map +1 -1
- package/dist/tsup/index.d.cts +65 -3
- package/dist/tsup/index.d.ts +65 -3
- package/dist/tsup/index.js +1 -1
- package/dist/tsup/testing.cjs +29 -23
- package/dist/tsup/testing.cjs.map +1 -1
- package/dist/tsup/testing.d.cts +2 -1
- package/dist/tsup/testing.d.ts +2 -1
- package/dist/tsup/testing.js +7 -1
- package/dist/tsup/testing.js.map +1 -1
- package/package.json +2 -2
- package/schemas/serde.ts +16 -0
- package/schemas/v1.bare +10 -1
- package/schemas/versioned.ts +1 -0
- package/src/context.ts +108 -2
- package/src/driver.ts +51 -0
- package/src/index.ts +88 -22
- package/src/keys.ts +1 -0
- package/src/storage.ts +52 -16
- package/src/testing.ts +7 -0
- package/src/types.ts +17 -2
- package/dist/tsup/chunk-GQWOLYBA.cjs.map +0 -1
- package/dist/tsup/chunk-KA2T56AJ.js.map +0 -1
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 batchDelete(keys: Uint8Array[]): Promise<void> {\n\t\tawait sleep(this.latency);\n\t\tfor (const key of keys) {\n\t\t\tthis.kv.delete(keyToHex(key));\n\t\t}\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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rivetkit/workflow-engine",
|
|
3
|
-
"version": "0.0.0-sqlite-
|
|
3
|
+
"version": "0.0.0-sqlite-sync-3-0-0-release.14341d0",
|
|
4
4
|
"description": "Durable workflow engine with reentrant execution",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"keywords": [
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
},
|
|
70
70
|
"repository": {
|
|
71
71
|
"type": "git",
|
|
72
|
-
"url": "https://github.com/rivet-dev/
|
|
72
|
+
"url": "https://github.com/rivet-dev/rivet.git",
|
|
73
73
|
"directory": "rivetkit-typescript/packages/workflow-engine"
|
|
74
74
|
}
|
|
75
75
|
}
|
package/schemas/serde.ts
CHANGED
|
@@ -307,6 +307,14 @@ function entryKindToBare(kind: InternalEntryKind): v1.EntryKind {
|
|
|
307
307
|
originalName: kind.data.originalName ?? null,
|
|
308
308
|
},
|
|
309
309
|
};
|
|
310
|
+
case "version_check":
|
|
311
|
+
return {
|
|
312
|
+
tag: "VersionCheckEntry",
|
|
313
|
+
val: {
|
|
314
|
+
resolved: kind.data.resolved,
|
|
315
|
+
latest: kind.data.latest,
|
|
316
|
+
},
|
|
317
|
+
};
|
|
310
318
|
}
|
|
311
319
|
}
|
|
312
320
|
|
|
@@ -396,6 +404,14 @@ function entryKindFromBare(kind: v1.EntryKind): InternalEntryKind {
|
|
|
396
404
|
originalName: kind.val.originalName ?? undefined,
|
|
397
405
|
},
|
|
398
406
|
};
|
|
407
|
+
case "VersionCheckEntry":
|
|
408
|
+
return {
|
|
409
|
+
type: "version_check",
|
|
410
|
+
data: {
|
|
411
|
+
resolved: kind.val.resolved,
|
|
412
|
+
latest: kind.val.latest,
|
|
413
|
+
},
|
|
414
|
+
};
|
|
399
415
|
default:
|
|
400
416
|
throw new Error(
|
|
401
417
|
`Unknown entry kind: ${(kind as { tag: string }).tag}`,
|
package/schemas/v1.bare
CHANGED
|
@@ -122,6 +122,14 @@ type RemovedEntry struct {
|
|
|
122
122
|
originalName: optional<str>
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
+
# MARK: Version Check Entry
|
|
126
|
+
type VersionCheckEntry struct {
|
|
127
|
+
# The version this instance resolved to at this location
|
|
128
|
+
resolved: u32
|
|
129
|
+
# The `latest` value seen when first resolved (diagnostics)
|
|
130
|
+
latest: u32
|
|
131
|
+
}
|
|
132
|
+
|
|
125
133
|
# MARK: Entry Kind
|
|
126
134
|
# Type-specific entry data
|
|
127
135
|
type EntryKind union {
|
|
@@ -132,7 +140,8 @@ type EntryKind union {
|
|
|
132
140
|
RollbackCheckpointEntry |
|
|
133
141
|
JoinEntry |
|
|
134
142
|
RaceEntry |
|
|
135
|
-
RemovedEntry
|
|
143
|
+
RemovedEntry |
|
|
144
|
+
VersionCheckEntry
|
|
136
145
|
}
|
|
137
146
|
|
|
138
147
|
# MARK: Entry
|
package/schemas/versioned.ts
CHANGED
package/src/context.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Logger } from "pino";
|
|
2
|
-
import type { EngineDriver } from "./driver.js";
|
|
2
|
+
import type { EngineDriver, WorkflowSpan } from "./driver.js";
|
|
3
3
|
import {
|
|
4
4
|
extractErrorInfo,
|
|
5
5
|
getErrorEventTag,
|
|
@@ -345,6 +345,7 @@ export class WorkflowContextImpl implements WorkflowContextInterface {
|
|
|
345
345
|
private abortController: AbortController;
|
|
346
346
|
private currentLocation: Location;
|
|
347
347
|
private visitedKeys: Set<string>;
|
|
348
|
+
private runSpan?: WorkflowSpan;
|
|
348
349
|
private mode: "forward" | "rollback";
|
|
349
350
|
private rollbackActions?: RollbackAction[];
|
|
350
351
|
private rollbackCheckpointSet: boolean;
|
|
@@ -369,6 +370,7 @@ export class WorkflowContextImpl implements WorkflowContextInterface {
|
|
|
369
370
|
onError?: WorkflowErrorHandler,
|
|
370
371
|
logger?: Logger,
|
|
371
372
|
visitedKeys?: Set<string>,
|
|
373
|
+
runSpan?: WorkflowSpan,
|
|
372
374
|
) {
|
|
373
375
|
this.currentLocation = location;
|
|
374
376
|
this.abortController = abortController ?? new AbortController();
|
|
@@ -379,6 +381,7 @@ export class WorkflowContextImpl implements WorkflowContextInterface {
|
|
|
379
381
|
this.onError = onError;
|
|
380
382
|
this.logger = logger;
|
|
381
383
|
this.visitedKeys = visitedKeys ?? new Set();
|
|
384
|
+
this.runSpan = runSpan;
|
|
382
385
|
}
|
|
383
386
|
|
|
384
387
|
get abortSignal(): AbortSignal {
|
|
@@ -435,6 +438,7 @@ export class WorkflowContextImpl implements WorkflowContextInterface {
|
|
|
435
438
|
this.onError,
|
|
436
439
|
this.logger,
|
|
437
440
|
this.visitedKeys,
|
|
441
|
+
this.runSpan,
|
|
438
442
|
);
|
|
439
443
|
}
|
|
440
444
|
|
|
@@ -906,10 +910,15 @@ export class WorkflowContextImpl implements WorkflowContextInterface {
|
|
|
906
910
|
// Get timeout configuration
|
|
907
911
|
const timeout = config.timeout ?? DEFAULT_STEP_TIMEOUT;
|
|
908
912
|
|
|
913
|
+
const stepSpan = this.runSpan?.startStep(
|
|
914
|
+
config.name,
|
|
915
|
+
metadata.attempts,
|
|
916
|
+
);
|
|
917
|
+
|
|
909
918
|
try {
|
|
910
919
|
// Execute with timeout
|
|
911
920
|
const output = await this.executeWithTimeout(
|
|
912
|
-
config.run(),
|
|
921
|
+
stepSpan ? stepSpan.run(() => config.run()) : config.run(),
|
|
913
922
|
timeout,
|
|
914
923
|
config.name,
|
|
915
924
|
);
|
|
@@ -936,6 +945,7 @@ export class WorkflowContextImpl implements WorkflowContextInterface {
|
|
|
936
945
|
await this.flushStorage();
|
|
937
946
|
}
|
|
938
947
|
|
|
948
|
+
stepSpan?.finish("ok");
|
|
939
949
|
this.log("debug", {
|
|
940
950
|
msg: "step completed",
|
|
941
951
|
step: config.name,
|
|
@@ -951,6 +961,7 @@ export class WorkflowContextImpl implements WorkflowContextInterface {
|
|
|
951
961
|
// Timeout errors are treated as critical by default. Steps opt
|
|
952
962
|
// into retrying on timeout with retryOnTimeout: true.
|
|
953
963
|
if (error instanceof StepTimeoutError && !config.retryOnTimeout) {
|
|
964
|
+
stepSpan?.finish("failed", error);
|
|
954
965
|
metadata.status = "exhausted";
|
|
955
966
|
metadata.error = String(error);
|
|
956
967
|
await this.notifyStepError(config, metadata.attempts, error, {
|
|
@@ -970,6 +981,7 @@ export class WorkflowContextImpl implements WorkflowContextInterface {
|
|
|
970
981
|
error instanceof CriticalError ||
|
|
971
982
|
error instanceof RollbackError
|
|
972
983
|
) {
|
|
984
|
+
stepSpan?.finish("failed", error);
|
|
973
985
|
metadata.status = "exhausted";
|
|
974
986
|
metadata.error = String(error);
|
|
975
987
|
await this.notifyStepError(config, metadata.attempts, error, {
|
|
@@ -989,6 +1001,7 @@ export class WorkflowContextImpl implements WorkflowContextInterface {
|
|
|
989
1001
|
}
|
|
990
1002
|
|
|
991
1003
|
const willRetry = metadata.attempts <= maxRetries;
|
|
1004
|
+
stepSpan?.finish(willRetry ? "retry" : "failed", error);
|
|
992
1005
|
metadata.status = willRetry ? "failed" : "exhausted";
|
|
993
1006
|
metadata.error = String(error);
|
|
994
1007
|
|
|
@@ -2581,4 +2594,97 @@ export class WorkflowContextImpl implements WorkflowContextInterface {
|
|
|
2581
2594
|
setEntry(this.storage, location, entry);
|
|
2582
2595
|
await this.flushStorage();
|
|
2583
2596
|
}
|
|
2597
|
+
|
|
2598
|
+
// === Version ===
|
|
2599
|
+
|
|
2600
|
+
async getVersion(name: string, latest: number): Promise<number> {
|
|
2601
|
+
this.assertNotInProgress();
|
|
2602
|
+
this.checkEvicted();
|
|
2603
|
+
|
|
2604
|
+
this.entryInProgress = true;
|
|
2605
|
+
try {
|
|
2606
|
+
return await this.executeGetVersion(name, latest);
|
|
2607
|
+
} finally {
|
|
2608
|
+
this.entryInProgress = false;
|
|
2609
|
+
}
|
|
2610
|
+
}
|
|
2611
|
+
|
|
2612
|
+
private async executeGetVersion(
|
|
2613
|
+
name: string,
|
|
2614
|
+
latest: number,
|
|
2615
|
+
): Promise<number> {
|
|
2616
|
+
if (!Number.isInteger(latest) || latest < 1) {
|
|
2617
|
+
throw new Error(
|
|
2618
|
+
`getVersion("${name}", ${latest}): latest must be an integer >= 1`,
|
|
2619
|
+
);
|
|
2620
|
+
}
|
|
2621
|
+
|
|
2622
|
+
// Check for duplicate name in current execution
|
|
2623
|
+
this.checkDuplicateName(name);
|
|
2624
|
+
|
|
2625
|
+
const location = appendName(this.storage, this.currentLocation, name);
|
|
2626
|
+
const key = locationToKey(this.storage, location);
|
|
2627
|
+
const existing = this.storage.history.entries.get(key);
|
|
2628
|
+
|
|
2629
|
+
// Mark this entry as visited for validateComplete
|
|
2630
|
+
this.markVisited(key);
|
|
2631
|
+
|
|
2632
|
+
this.stopRollbackIfMissing(existing);
|
|
2633
|
+
|
|
2634
|
+
if (existing) {
|
|
2635
|
+
if (existing.kind.type !== "version_check") {
|
|
2636
|
+
throw new HistoryDivergedError(
|
|
2637
|
+
`Expected version_check at ${key}, found ${existing.kind.type}`,
|
|
2638
|
+
);
|
|
2639
|
+
}
|
|
2640
|
+
// Pure replay: this instance is already pinned at this location.
|
|
2641
|
+
return existing.kind.data.resolved;
|
|
2642
|
+
}
|
|
2643
|
+
|
|
2644
|
+
// No recorded version at this location. Decide whether this instance
|
|
2645
|
+
// already executed past this point under older code (old in-flight) or
|
|
2646
|
+
// is reaching it fresh at the live frontier.
|
|
2647
|
+
//
|
|
2648
|
+
// The discriminator is "is there any unvisited history entry under the
|
|
2649
|
+
// current scope?". Entries created earlier in this same run are already
|
|
2650
|
+
// marked visited, so the only unvisited entries under the scope are
|
|
2651
|
+
// leftovers from a prior run, which proves this scope already executed
|
|
2652
|
+
// under code that predates this gate. Such instances resolve to the
|
|
2653
|
+
// implicit floor version 1 (old branch); fresh instances resolve to
|
|
2654
|
+
// `latest`.
|
|
2655
|
+
const resolved = this.hasUnvisitedUnderCurrentScope(key) ? 1 : latest;
|
|
2656
|
+
|
|
2657
|
+
const entry = createEntry(location, {
|
|
2658
|
+
type: "version_check",
|
|
2659
|
+
data: { resolved, latest },
|
|
2660
|
+
});
|
|
2661
|
+
setEntry(this.storage, location, entry);
|
|
2662
|
+
await this.flushStorage();
|
|
2663
|
+
|
|
2664
|
+
return resolved;
|
|
2665
|
+
}
|
|
2666
|
+
|
|
2667
|
+
/**
|
|
2668
|
+
* Returns true if any history entry under the current location scope
|
|
2669
|
+
* (other than `excludeKey`) has not yet been visited this run. Used by
|
|
2670
|
+
* getVersion to detect an old in-flight instance whose scope was already
|
|
2671
|
+
* executed by code that predates a version gate.
|
|
2672
|
+
*/
|
|
2673
|
+
private hasUnvisitedUnderCurrentScope(excludeKey: string): boolean {
|
|
2674
|
+
const prefix = locationToKey(this.storage, this.currentLocation);
|
|
2675
|
+
|
|
2676
|
+
for (const key of this.storage.history.entries.keys()) {
|
|
2677
|
+
if (key === excludeKey) {
|
|
2678
|
+
continue;
|
|
2679
|
+
}
|
|
2680
|
+
const isUnderPrefix =
|
|
2681
|
+
prefix === ""
|
|
2682
|
+
? true
|
|
2683
|
+
: key.startsWith(`${prefix}/`) || key === prefix;
|
|
2684
|
+
if (isUnderPrefix && !this.visitedKeys.has(key)) {
|
|
2685
|
+
return true;
|
|
2686
|
+
}
|
|
2687
|
+
}
|
|
2688
|
+
return false;
|
|
2689
|
+
}
|
|
2584
2690
|
}
|
package/src/driver.ts
CHANGED
|
@@ -16,6 +16,42 @@ export interface KVWrite {
|
|
|
16
16
|
value: Uint8Array;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
/** How one run of the workflow function ended. */
|
|
20
|
+
export type WorkflowOutcome =
|
|
21
|
+
| "completed"
|
|
22
|
+
| "sleeping"
|
|
23
|
+
| "evicted"
|
|
24
|
+
| "failed"
|
|
25
|
+
| "cancelled";
|
|
26
|
+
|
|
27
|
+
/** How one step attempt ended. `retry` will be tried again, `failed` will not. */
|
|
28
|
+
export type WorkflowStepOutcome = "ok" | "retry" | "failed";
|
|
29
|
+
|
|
30
|
+
/** One open run of the workflow function. */
|
|
31
|
+
export interface WorkflowSpan {
|
|
32
|
+
/** Runs `body` attributed to this run. */
|
|
33
|
+
run<T>(body: () => Promise<T>): Promise<T>;
|
|
34
|
+
/** Returns nothing when the attempt is not being traced. */
|
|
35
|
+
startStep(name: string, attempt: number): WorkflowStepSpan | undefined;
|
|
36
|
+
finish(outcome: WorkflowOutcome): Promise<void>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** One open attempt at one step. */
|
|
40
|
+
export interface WorkflowStepSpan {
|
|
41
|
+
/** Runs `body` attributed to this attempt. */
|
|
42
|
+
run<T>(body: () => Promise<T>): Promise<T>;
|
|
43
|
+
/** `error` is what the step callback threw. */
|
|
44
|
+
finish(outcome: WorkflowStepOutcome, error?: unknown): void;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Receives the start and end of each workflow run and step attempt. A
|
|
49
|
+
* completed step replayed from history is not an attempt and is not reported.
|
|
50
|
+
*/
|
|
51
|
+
export interface WorkflowTelemetryDriver {
|
|
52
|
+
startSpan(): Promise<WorkflowSpan>;
|
|
53
|
+
}
|
|
54
|
+
|
|
19
55
|
/**
|
|
20
56
|
* The engine driver provides the KV and scheduling interface.
|
|
21
57
|
* Implementations must provide these methods to integrate with different backends.
|
|
@@ -30,6 +66,12 @@ export interface KVWrite {
|
|
|
30
66
|
* See architecture.md "Isolation Model" for details.
|
|
31
67
|
*/
|
|
32
68
|
export interface EngineDriver {
|
|
69
|
+
/**
|
|
70
|
+
* Requires each logical storage flush to reach `batch` as one indivisible
|
|
71
|
+
* unit. The driver must reject an oversized unit instead of splitting it.
|
|
72
|
+
*/
|
|
73
|
+
readonly atomicBatch?: boolean;
|
|
74
|
+
|
|
33
75
|
// === KV Operations ===
|
|
34
76
|
|
|
35
77
|
/**
|
|
@@ -48,6 +90,12 @@ export interface EngineDriver {
|
|
|
48
90
|
*/
|
|
49
91
|
delete(key: Uint8Array): Promise<void>;
|
|
50
92
|
|
|
93
|
+
/**
|
|
94
|
+
* Batch delete multiple keys in a single operation.
|
|
95
|
+
* Should be atomic if possible.
|
|
96
|
+
*/
|
|
97
|
+
batchDelete(keys: Uint8Array[]): Promise<void>;
|
|
98
|
+
|
|
51
99
|
/**
|
|
52
100
|
* Delete all keys with a given prefix.
|
|
53
101
|
*/
|
|
@@ -105,4 +153,7 @@ export interface EngineDriver {
|
|
|
105
153
|
messageNames: string[],
|
|
106
154
|
abortSignal: AbortSignal,
|
|
107
155
|
): Promise<void>;
|
|
156
|
+
|
|
157
|
+
/** Present when the host traces workflows. */
|
|
158
|
+
readonly telemetry?: WorkflowTelemetryDriver;
|
|
108
159
|
}
|
package/src/index.ts
CHANGED
|
@@ -12,7 +12,16 @@ export {
|
|
|
12
12
|
WorkflowContextImpl,
|
|
13
13
|
} from "./context.js";
|
|
14
14
|
// Driver
|
|
15
|
-
export type {
|
|
15
|
+
export type {
|
|
16
|
+
EngineDriver,
|
|
17
|
+
KVEntry,
|
|
18
|
+
KVWrite,
|
|
19
|
+
WorkflowOutcome,
|
|
20
|
+
WorkflowSpan,
|
|
21
|
+
WorkflowStepOutcome,
|
|
22
|
+
WorkflowStepSpan,
|
|
23
|
+
WorkflowTelemetryDriver,
|
|
24
|
+
} from "./driver.js";
|
|
16
25
|
export { extractErrorInfo } from "./error-utils.js";
|
|
17
26
|
// Errors
|
|
18
27
|
export {
|
|
@@ -143,7 +152,7 @@ import {
|
|
|
143
152
|
} from "../schemas/serde.js";
|
|
144
153
|
import { type RollbackAction, WorkflowContextImpl } from "./context.js";
|
|
145
154
|
// Main workflow runner
|
|
146
|
-
import type { EngineDriver } from "./driver.js";
|
|
155
|
+
import type { EngineDriver, WorkflowOutcome, WorkflowSpan } from "./driver.js";
|
|
147
156
|
import {
|
|
148
157
|
extractErrorInfo,
|
|
149
158
|
getErrorEventTag,
|
|
@@ -288,6 +297,7 @@ async function executeRollback<TInput, TOutput>(
|
|
|
288
297
|
historyNotifier?: HistoryNotifier,
|
|
289
298
|
onError?: RunWorkflowOptions["onError"],
|
|
290
299
|
logger?: Logger,
|
|
300
|
+
runSpan?: WorkflowSpan,
|
|
291
301
|
): Promise<void> {
|
|
292
302
|
const rollbackActions: RollbackAction[] = [];
|
|
293
303
|
const ctx = new WorkflowContextImpl(
|
|
@@ -303,6 +313,8 @@ async function executeRollback<TInput, TOutput>(
|
|
|
303
313
|
historyNotifier,
|
|
304
314
|
onError,
|
|
305
315
|
logger,
|
|
316
|
+
undefined,
|
|
317
|
+
runSpan,
|
|
306
318
|
);
|
|
307
319
|
|
|
308
320
|
try {
|
|
@@ -511,16 +523,19 @@ async function executeLiveWorkflow<TInput, TOutput>(
|
|
|
511
523
|
let lastResult: WorkflowResult<TOutput> | undefined;
|
|
512
524
|
|
|
513
525
|
while (true) {
|
|
514
|
-
const result = await
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
526
|
+
const result = await traceRun(driver, (runSpan) =>
|
|
527
|
+
executeWorkflow(
|
|
528
|
+
workflowId,
|
|
529
|
+
workflowFn,
|
|
530
|
+
input,
|
|
531
|
+
driver,
|
|
532
|
+
messageDriver,
|
|
533
|
+
abortController,
|
|
534
|
+
onHistoryUpdated,
|
|
535
|
+
onError,
|
|
536
|
+
logger,
|
|
537
|
+
runSpan,
|
|
538
|
+
),
|
|
524
539
|
);
|
|
525
540
|
lastResult = result;
|
|
526
541
|
|
|
@@ -642,16 +657,19 @@ export function runWorkflow<TInput, TOutput>(
|
|
|
642
657
|
options.onError,
|
|
643
658
|
logger,
|
|
644
659
|
)
|
|
645
|
-
:
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
660
|
+
: traceRun(driver, (runSpan) =>
|
|
661
|
+
executeWorkflow(
|
|
662
|
+
workflowId,
|
|
663
|
+
workflowFn,
|
|
664
|
+
input,
|
|
665
|
+
driver,
|
|
666
|
+
messageDriver,
|
|
667
|
+
abortController,
|
|
668
|
+
options.onHistoryUpdated,
|
|
669
|
+
options.onError,
|
|
670
|
+
logger,
|
|
671
|
+
runSpan,
|
|
672
|
+
),
|
|
655
673
|
);
|
|
656
674
|
|
|
657
675
|
return {
|
|
@@ -886,6 +904,49 @@ function findReplayBoundaryEntry(
|
|
|
886
904
|
return boundary;
|
|
887
905
|
}
|
|
888
906
|
|
|
907
|
+
function runOutcomeFromState(state: WorkflowState): WorkflowOutcome {
|
|
908
|
+
switch (state) {
|
|
909
|
+
case "completed":
|
|
910
|
+
return "completed";
|
|
911
|
+
case "sleeping":
|
|
912
|
+
return "sleeping";
|
|
913
|
+
case "failed":
|
|
914
|
+
return "failed";
|
|
915
|
+
case "cancelled":
|
|
916
|
+
return "cancelled";
|
|
917
|
+
case "pending":
|
|
918
|
+
case "running":
|
|
919
|
+
case "rolling_back":
|
|
920
|
+
return "evicted";
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
/** Internal: Report one workflow run to the driver's telemetry, when it has any. */
|
|
925
|
+
async function traceRun<TOutput>(
|
|
926
|
+
driver: EngineDriver,
|
|
927
|
+
run: (span?: WorkflowSpan) => Promise<WorkflowResult<TOutput>>,
|
|
928
|
+
): Promise<WorkflowResult<TOutput>> {
|
|
929
|
+
if (!driver.telemetry) {
|
|
930
|
+
return await run();
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
const span = await driver.telemetry.startSpan();
|
|
934
|
+
let outcome: WorkflowOutcome = "failed";
|
|
935
|
+
try {
|
|
936
|
+
const result = await span.run(() => run(span));
|
|
937
|
+
outcome = runOutcomeFromState(result.state);
|
|
938
|
+
return result;
|
|
939
|
+
} catch (error) {
|
|
940
|
+
// A run throws EvictedError only when the workflow was already cancelled.
|
|
941
|
+
if (error instanceof EvictedError) {
|
|
942
|
+
outcome = "cancelled";
|
|
943
|
+
}
|
|
944
|
+
throw error;
|
|
945
|
+
} finally {
|
|
946
|
+
await span.finish(outcome);
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
|
|
889
950
|
/**
|
|
890
951
|
* Internal: Execute the workflow and return the result.
|
|
891
952
|
*/
|
|
@@ -899,6 +960,7 @@ async function executeWorkflow<TInput, TOutput>(
|
|
|
899
960
|
onHistoryUpdated?: (history: WorkflowHistorySnapshot) => void,
|
|
900
961
|
onError?: RunWorkflowOptions["onError"],
|
|
901
962
|
logger?: Logger,
|
|
963
|
+
runSpan?: WorkflowSpan,
|
|
902
964
|
): Promise<WorkflowResult<TOutput>> {
|
|
903
965
|
const storage = await loadStorage(driver);
|
|
904
966
|
const historyNotifier: HistoryNotifier = onHistoryUpdated
|
|
@@ -953,6 +1015,7 @@ async function executeWorkflow<TInput, TOutput>(
|
|
|
953
1015
|
historyNotifier,
|
|
954
1016
|
onError,
|
|
955
1017
|
logger,
|
|
1018
|
+
runSpan,
|
|
956
1019
|
);
|
|
957
1020
|
} catch (error) {
|
|
958
1021
|
if (error instanceof EvictedError) {
|
|
@@ -986,6 +1049,8 @@ async function executeWorkflow<TInput, TOutput>(
|
|
|
986
1049
|
historyNotifier,
|
|
987
1050
|
onError,
|
|
988
1051
|
logger,
|
|
1052
|
+
undefined,
|
|
1053
|
+
runSpan,
|
|
989
1054
|
);
|
|
990
1055
|
|
|
991
1056
|
storage.state = "running";
|
|
@@ -1064,6 +1129,7 @@ async function executeWorkflow<TInput, TOutput>(
|
|
|
1064
1129
|
historyNotifier,
|
|
1065
1130
|
onError,
|
|
1066
1131
|
logger,
|
|
1132
|
+
runSpan,
|
|
1067
1133
|
);
|
|
1068
1134
|
} catch (rollbackError) {
|
|
1069
1135
|
if (rollbackError instanceof EvictedError) {
|
package/src/keys.ts
CHANGED
|
@@ -14,6 +14,7 @@ export const KEY_PREFIX = {
|
|
|
14
14
|
HISTORY: 2, // History entries: [2, ...locationSegments]
|
|
15
15
|
WORKFLOW: 3, // Workflow metadata: [3, field]
|
|
16
16
|
ENTRY_METADATA: 4, // Entry metadata: [4, entryId]
|
|
17
|
+
// 5 is reserved for RivetKit's workflow trace context.
|
|
17
18
|
} as const;
|
|
18
19
|
|
|
19
20
|
// Workflow metadata field identifiers
|