@rivetkit/workflow-engine 2.3.0-rc.1 → 2.3.0-rc.11
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-UMFB2AR3.js → chunk-DFNXCZ47.js} +60 -36
- package/dist/tsup/chunk-DFNXCZ47.js.map +1 -0
- package/dist/tsup/{chunk-4SWXLWKL.cjs → chunk-U2W3KHJC.cjs} +60 -36
- package/dist/tsup/chunk-U2W3KHJC.cjs.map +1 -0
- package/dist/tsup/index.cjs +2 -2
- package/dist/tsup/index.d.cts +17 -7
- package/dist/tsup/index.d.ts +17 -7
- package/dist/tsup/index.js +1 -1
- package/dist/tsup/testing.cjs +23 -23
- package/dist/tsup/testing.js +1 -1
- package/package.json +1 -1
- package/schemas/serde.ts +1 -3
- package/src/context.ts +33 -41
- package/src/index.ts +8 -8
- package/src/location.ts +1 -1
- package/src/storage.ts +50 -3
- package/src/types.ts +10 -6
- package/dist/tsup/chunk-4SWXLWKL.cjs.map +0 -1
- package/dist/tsup/chunk-UMFB2AR3.js.map +0 -1
|
@@ -1402,6 +1402,8 @@ function deserializeName(bytes) {
|
|
|
1402
1402
|
}
|
|
1403
1403
|
|
|
1404
1404
|
// src/storage.ts
|
|
1405
|
+
var MAX_KV_BATCH_ENTRIES = 128;
|
|
1406
|
+
var MAX_KV_BATCH_PAYLOAD_BYTES = 976 * 1024;
|
|
1405
1407
|
function createStorage() {
|
|
1406
1408
|
return {
|
|
1407
1409
|
nameRegistry: [],
|
|
@@ -1519,6 +1521,8 @@ async function loadMetadata(storage, driver, entryId) {
|
|
|
1519
1521
|
}
|
|
1520
1522
|
async function flush(storage, driver, onHistoryUpdated, pendingDeletions) {
|
|
1521
1523
|
const writes = [];
|
|
1524
|
+
const dirtyEntries = [];
|
|
1525
|
+
const dirtyMetadata = [];
|
|
1522
1526
|
let historyUpdated = false;
|
|
1523
1527
|
for (let i = storage.flushedNameCount; i < storage.nameRegistry.length; i++) {
|
|
1524
1528
|
const name = storage.nameRegistry[i];
|
|
@@ -1536,7 +1540,7 @@ async function flush(storage, driver, onHistoryUpdated, pendingDeletions) {
|
|
|
1536
1540
|
key: buildHistoryKey(entry.location),
|
|
1537
1541
|
value: serializeEntry(entry)
|
|
1538
1542
|
});
|
|
1539
|
-
entry
|
|
1543
|
+
dirtyEntries.push(entry);
|
|
1540
1544
|
historyUpdated = true;
|
|
1541
1545
|
}
|
|
1542
1546
|
}
|
|
@@ -1546,7 +1550,7 @@ async function flush(storage, driver, onHistoryUpdated, pendingDeletions) {
|
|
|
1546
1550
|
key: buildEntryMetadataKey(id),
|
|
1547
1551
|
value: serializeEntryMetadata(metadata)
|
|
1548
1552
|
});
|
|
1549
|
-
metadata
|
|
1553
|
+
dirtyMetadata.push(metadata);
|
|
1550
1554
|
historyUpdated = true;
|
|
1551
1555
|
}
|
|
1552
1556
|
}
|
|
@@ -1570,7 +1574,9 @@ async function flush(storage, driver, onHistoryUpdated, pendingDeletions) {
|
|
|
1570
1574
|
});
|
|
1571
1575
|
}
|
|
1572
1576
|
if (writes.length > 0) {
|
|
1573
|
-
|
|
1577
|
+
for (const chunk of splitBatchWrites(writes)) {
|
|
1578
|
+
await driver.batch(chunk);
|
|
1579
|
+
}
|
|
1574
1580
|
}
|
|
1575
1581
|
if (pendingDeletions) {
|
|
1576
1582
|
const deleteOps = [];
|
|
@@ -1588,6 +1594,12 @@ async function flush(storage, driver, onHistoryUpdated, pendingDeletions) {
|
|
|
1588
1594
|
historyUpdated = true;
|
|
1589
1595
|
}
|
|
1590
1596
|
}
|
|
1597
|
+
for (const entry of dirtyEntries) {
|
|
1598
|
+
entry.dirty = false;
|
|
1599
|
+
}
|
|
1600
|
+
for (const metadata of dirtyMetadata) {
|
|
1601
|
+
metadata.dirty = false;
|
|
1602
|
+
}
|
|
1591
1603
|
storage.flushedNameCount = storage.nameRegistry.length;
|
|
1592
1604
|
storage.flushedState = storage.state;
|
|
1593
1605
|
storage.flushedOutput = storage.output;
|
|
@@ -1596,6 +1608,30 @@ async function flush(storage, driver, onHistoryUpdated, pendingDeletions) {
|
|
|
1596
1608
|
onHistoryUpdated();
|
|
1597
1609
|
}
|
|
1598
1610
|
}
|
|
1611
|
+
function splitBatchWrites(writes) {
|
|
1612
|
+
const chunks = [];
|
|
1613
|
+
let chunk = [];
|
|
1614
|
+
let chunkBytes = 0;
|
|
1615
|
+
for (const write of writes) {
|
|
1616
|
+
const writeBytes = write.key.byteLength + write.value.byteLength;
|
|
1617
|
+
if (writeBytes > MAX_KV_BATCH_PAYLOAD_BYTES) {
|
|
1618
|
+
throw new Error(
|
|
1619
|
+
`KV batch write is ${writeBytes} bytes, exceeding the ${MAX_KV_BATCH_PAYLOAD_BYTES} byte limit`
|
|
1620
|
+
);
|
|
1621
|
+
}
|
|
1622
|
+
if (chunk.length >= MAX_KV_BATCH_ENTRIES || chunk.length > 0 && chunkBytes + writeBytes > MAX_KV_BATCH_PAYLOAD_BYTES) {
|
|
1623
|
+
chunks.push(chunk);
|
|
1624
|
+
chunk = [];
|
|
1625
|
+
chunkBytes = 0;
|
|
1626
|
+
}
|
|
1627
|
+
chunk.push(write);
|
|
1628
|
+
chunkBytes += writeBytes;
|
|
1629
|
+
}
|
|
1630
|
+
if (chunk.length > 0) {
|
|
1631
|
+
chunks.push(chunk);
|
|
1632
|
+
}
|
|
1633
|
+
return chunks;
|
|
1634
|
+
}
|
|
1599
1635
|
async function deleteEntriesWithPrefix(storage, driver, prefixLocation, onHistoryUpdated) {
|
|
1600
1636
|
const deletions = collectDeletionsForPrefix(storage, prefixLocation);
|
|
1601
1637
|
await driver.deletePrefix(deletions.prefixes[0]);
|
|
@@ -1927,7 +1963,7 @@ var WorkflowContextImpl = class _WorkflowContextImpl {
|
|
|
1927
1963
|
* Throws HistoryDivergedError if duplicate detected.
|
|
1928
1964
|
*/
|
|
1929
1965
|
checkDuplicateName(name) {
|
|
1930
|
-
const fullKey = locationToKey(this.storage, this.currentLocation)
|
|
1966
|
+
const fullKey = `${locationToKey(this.storage, this.currentLocation)}/${name}`;
|
|
1931
1967
|
if (this.usedNamesInExecution.has(fullKey)) {
|
|
1932
1968
|
throw new HistoryDivergedError(
|
|
1933
1969
|
`Duplicate entry name "${name}" at location "${locationToKey(this.storage, this.currentLocation)}". Each step/loop/sleep/queue.next/join/race must have a unique name within its scope.`
|
|
@@ -1981,7 +2017,7 @@ var WorkflowContextImpl = class _WorkflowContextImpl {
|
|
|
1981
2017
|
validateComplete() {
|
|
1982
2018
|
const prefix = locationToKey(this.storage, this.currentLocation);
|
|
1983
2019
|
for (const key of this.storage.history.entries.keys()) {
|
|
1984
|
-
const isUnderPrefix = prefix === "" ? true : key.startsWith(prefix
|
|
2020
|
+
const isUnderPrefix = prefix === "" ? true : key.startsWith(`${prefix}/`) || key === prefix;
|
|
1985
2021
|
if (isUnderPrefix) {
|
|
1986
2022
|
if (!this.visitedKeys.has(key)) {
|
|
1987
2023
|
throw new HistoryDivergedError(
|
|
@@ -2165,7 +2201,7 @@ var WorkflowContextImpl = class _WorkflowContextImpl {
|
|
|
2165
2201
|
}
|
|
2166
2202
|
const maxRetries2 = config2.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
2167
2203
|
if (metadata2.attempts > maxRetries2) {
|
|
2168
|
-
const lastError =
|
|
2204
|
+
const lastError = metadata2.error;
|
|
2169
2205
|
const exhaustedError = new StepExhaustedError(
|
|
2170
2206
|
config2.name,
|
|
2171
2207
|
lastError
|
|
@@ -2254,37 +2290,28 @@ var WorkflowContextImpl = class _WorkflowContextImpl {
|
|
|
2254
2290
|
});
|
|
2255
2291
|
return output;
|
|
2256
2292
|
} catch (error) {
|
|
2257
|
-
if (
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2293
|
+
if (entry.kind.type === "step") {
|
|
2294
|
+
entry.kind.data.error = String(error);
|
|
2295
|
+
}
|
|
2296
|
+
entry.dirty = true;
|
|
2297
|
+
if (error instanceof StepTimeoutError && !config2.retryOnTimeout) {
|
|
2262
2298
|
metadata.status = "exhausted";
|
|
2263
2299
|
metadata.error = String(error);
|
|
2264
|
-
await this.flushStorage();
|
|
2265
2300
|
await this.notifyStepError(config2, metadata.attempts, error, {
|
|
2266
2301
|
willRetry: false
|
|
2267
2302
|
});
|
|
2268
2303
|
throw markErrorReported(
|
|
2269
|
-
attachTryStepFailure(
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
error: extractErrorInfo(error)
|
|
2276
|
-
}
|
|
2277
|
-
)
|
|
2304
|
+
attachTryStepFailure(new CriticalError(error.message), {
|
|
2305
|
+
kind: "timeout",
|
|
2306
|
+
stepName: config2.name,
|
|
2307
|
+
attempts: metadata.attempts,
|
|
2308
|
+
error: extractErrorInfo(error)
|
|
2309
|
+
})
|
|
2278
2310
|
);
|
|
2279
2311
|
}
|
|
2280
2312
|
if (error instanceof CriticalError || error instanceof RollbackError) {
|
|
2281
|
-
if (entry.kind.type === "step") {
|
|
2282
|
-
entry.kind.data.error = String(error);
|
|
2283
|
-
}
|
|
2284
|
-
entry.dirty = true;
|
|
2285
2313
|
metadata.status = "exhausted";
|
|
2286
2314
|
metadata.error = String(error);
|
|
2287
|
-
await this.flushStorage();
|
|
2288
2315
|
await this.notifyStepError(config2, metadata.attempts, error, {
|
|
2289
2316
|
willRetry: false
|
|
2290
2317
|
});
|
|
@@ -2297,14 +2324,9 @@ var WorkflowContextImpl = class _WorkflowContextImpl {
|
|
|
2297
2324
|
})
|
|
2298
2325
|
);
|
|
2299
2326
|
}
|
|
2300
|
-
if (entry.kind.type === "step") {
|
|
2301
|
-
entry.kind.data.error = String(error);
|
|
2302
|
-
}
|
|
2303
|
-
entry.dirty = true;
|
|
2304
2327
|
const willRetry = metadata.attempts <= maxRetries;
|
|
2305
2328
|
metadata.status = willRetry ? "failed" : "exhausted";
|
|
2306
2329
|
metadata.error = String(error);
|
|
2307
|
-
await this.flushStorage();
|
|
2308
2330
|
if (willRetry) {
|
|
2309
2331
|
const retryDelay = calculateBackoff(
|
|
2310
2332
|
metadata.attempts,
|
|
@@ -2328,7 +2350,7 @@ var WorkflowContextImpl = class _WorkflowContextImpl {
|
|
|
2328
2350
|
attachTryStepFailure(
|
|
2329
2351
|
new StepExhaustedError(config2.name, String(error)),
|
|
2330
2352
|
{
|
|
2331
|
-
kind: "exhausted",
|
|
2353
|
+
kind: error instanceof StepTimeoutError ? "timeout" : "exhausted",
|
|
2332
2354
|
stepName: config2.name,
|
|
2333
2355
|
attempts: metadata.attempts,
|
|
2334
2356
|
error: extractErrorInfo(error)
|
|
@@ -2346,7 +2368,9 @@ var WorkflowContextImpl = class _WorkflowContextImpl {
|
|
|
2346
2368
|
*
|
|
2347
2369
|
* Note: This does NOT cancel the underlying operation. JavaScript Promises
|
|
2348
2370
|
* cannot be cancelled once started. When a timeout occurs:
|
|
2349
|
-
* - The step is
|
|
2371
|
+
* - The step is rejected with StepTimeoutError. By default this is treated
|
|
2372
|
+
* as a critical failure with no retry. Set retryOnTimeout: true on the
|
|
2373
|
+
* step config to retry timeouts like any other error.
|
|
2350
2374
|
* - The underlying async operation continues running in the background
|
|
2351
2375
|
* - Any side effects from the operation may still occur
|
|
2352
2376
|
*
|
|
@@ -2481,8 +2505,8 @@ var WorkflowContextImpl = class _WorkflowContextImpl {
|
|
|
2481
2505
|
metadata.error = void 0;
|
|
2482
2506
|
metadata.dirty = true;
|
|
2483
2507
|
}
|
|
2484
|
-
const historyPruneInterval = config2.historyPruneInterval ?? DEFAULT_LOOP_HISTORY_PRUNE_INTERVAL;
|
|
2485
|
-
const historySize = config2.historySize ?? historyPruneInterval;
|
|
2508
|
+
const historyPruneInterval = config2.historyPruneInterval ?? config2.commitInterval ?? config2.historyEvery ?? DEFAULT_LOOP_HISTORY_PRUNE_INTERVAL;
|
|
2509
|
+
const historySize = config2.historySize ?? config2.historyKeep ?? historyPruneInterval;
|
|
2486
2510
|
let lastPrunedUpTo = 0;
|
|
2487
2511
|
let deferredFlush = null;
|
|
2488
2512
|
while (true) {
|
|
@@ -4177,4 +4201,4 @@ export {
|
|
|
4177
4201
|
runWorkflow,
|
|
4178
4202
|
replayWorkflowFromStep
|
|
4179
4203
|
};
|
|
4180
|
-
//# sourceMappingURL=chunk-
|
|
4204
|
+
//# sourceMappingURL=chunk-DFNXCZ47.js.map
|