@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
|
@@ -248,6 +248,13 @@ function parseNameKey(key) {
|
|
|
248
248
|
}
|
|
249
249
|
return elements[1];
|
|
250
250
|
}
|
|
251
|
+
function parseEntryMetadataKey(key) {
|
|
252
|
+
const elements = unpack2(key);
|
|
253
|
+
if (elements.length !== 2 || elements[0] !== KEY_PREFIX.ENTRY_METADATA) {
|
|
254
|
+
throw new Error("Invalid entry metadata key");
|
|
255
|
+
}
|
|
256
|
+
return elements[1];
|
|
257
|
+
}
|
|
251
258
|
function keyStartsWith(key, prefix) {
|
|
252
259
|
if (key.length < prefix.length) {
|
|
253
260
|
return false;
|
|
@@ -1472,6 +1479,13 @@ async function loadStorage(driver) {
|
|
|
1472
1479
|
const key = locationToKey(storage, parsed.location);
|
|
1473
1480
|
storage.history.entries.set(key, parsed);
|
|
1474
1481
|
}
|
|
1482
|
+
const metadataEntries = await driver.list(buildEntryMetadataPrefix());
|
|
1483
|
+
for (const entry of metadataEntries) {
|
|
1484
|
+
const entryId = parseEntryMetadataKey(entry.key);
|
|
1485
|
+
const metadata = deserializeEntryMetadata(entry.value);
|
|
1486
|
+
metadata.dirty = false;
|
|
1487
|
+
storage.entryMetadata.set(entryId, metadata);
|
|
1488
|
+
}
|
|
1475
1489
|
const stateValue = await driver.get(buildWorkflowStateKey());
|
|
1476
1490
|
if (stateValue) {
|
|
1477
1491
|
storage.state = deserializeWorkflowState(stateValue);
|
|
@@ -2033,16 +2047,11 @@ var WorkflowContextImpl = class _WorkflowContextImpl {
|
|
|
2033
2047
|
retryBackoffMax
|
|
2034
2048
|
);
|
|
2035
2049
|
const retryAt = metadata.lastAttemptAt + retryDelay;
|
|
2036
|
-
await this.notifyStepError(
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
willRetry: true,
|
|
2042
|
-
retryDelay,
|
|
2043
|
-
retryAt
|
|
2044
|
-
}
|
|
2045
|
-
);
|
|
2050
|
+
await this.notifyStepError(config2, metadata.attempts, error, {
|
|
2051
|
+
willRetry: true,
|
|
2052
|
+
retryDelay,
|
|
2053
|
+
retryAt
|
|
2054
|
+
});
|
|
2046
2055
|
throw new StepFailedError(
|
|
2047
2056
|
config2.name,
|
|
2048
2057
|
error,
|
|
@@ -2053,12 +2062,9 @@ var WorkflowContextImpl = class _WorkflowContextImpl {
|
|
|
2053
2062
|
const exhaustedError = markErrorReported(
|
|
2054
2063
|
new StepExhaustedError(config2.name, String(error))
|
|
2055
2064
|
);
|
|
2056
|
-
await this.notifyStepError(
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
error,
|
|
2060
|
-
{ willRetry: false }
|
|
2061
|
-
);
|
|
2065
|
+
await this.notifyStepError(config2, metadata.attempts, error, {
|
|
2066
|
+
willRetry: false
|
|
2067
|
+
});
|
|
2062
2068
|
throw exhaustedError;
|
|
2063
2069
|
}
|
|
2064
2070
|
}
|
|
@@ -3501,6 +3507,91 @@ function runWorkflow(workflowId, workflowFn, input, driver, options = {}) {
|
|
|
3501
3507
|
}
|
|
3502
3508
|
};
|
|
3503
3509
|
}
|
|
3510
|
+
async function replayWorkflowFromStep(workflowId, driver, entryId, options) {
|
|
3511
|
+
const storage = await loadStorage(driver);
|
|
3512
|
+
const entries = await Promise.all(
|
|
3513
|
+
Array.from(storage.history.entries.entries()).map(
|
|
3514
|
+
async ([key, entry]) => ({
|
|
3515
|
+
key,
|
|
3516
|
+
entry,
|
|
3517
|
+
metadata: await loadMetadata(storage, driver, entry.id)
|
|
3518
|
+
})
|
|
3519
|
+
)
|
|
3520
|
+
);
|
|
3521
|
+
const ordered = [...entries].sort((a, b) => {
|
|
3522
|
+
if (a.metadata.createdAt !== b.metadata.createdAt) {
|
|
3523
|
+
return a.metadata.createdAt - b.metadata.createdAt;
|
|
3524
|
+
}
|
|
3525
|
+
return a.key.localeCompare(b.key);
|
|
3526
|
+
});
|
|
3527
|
+
let entriesToDelete = ordered;
|
|
3528
|
+
if (entryId !== void 0) {
|
|
3529
|
+
const target = entries.find(({ entry }) => entry.id === entryId);
|
|
3530
|
+
if (!target) {
|
|
3531
|
+
throw new Error(`Workflow step not found: ${entryId}`);
|
|
3532
|
+
}
|
|
3533
|
+
if (target.entry.kind.type !== "step") {
|
|
3534
|
+
throw new Error("Workflow replay target must be a step");
|
|
3535
|
+
}
|
|
3536
|
+
const replayBoundary = findReplayBoundaryEntry(entries, target);
|
|
3537
|
+
const targetIndex = ordered.findIndex(
|
|
3538
|
+
({ entry }) => entry.id === replayBoundary.entry.id
|
|
3539
|
+
);
|
|
3540
|
+
entriesToDelete = ordered.slice(targetIndex);
|
|
3541
|
+
}
|
|
3542
|
+
const entryIdsToDelete = new Set(
|
|
3543
|
+
entriesToDelete.map(({ entry }) => entry.id)
|
|
3544
|
+
);
|
|
3545
|
+
if (entries.some(
|
|
3546
|
+
({ entry, metadata }) => metadata.status === "running" && !entryIdsToDelete.has(entry.id)
|
|
3547
|
+
)) {
|
|
3548
|
+
throw new Error(
|
|
3549
|
+
"Cannot replay a workflow while a step is currently running"
|
|
3550
|
+
);
|
|
3551
|
+
}
|
|
3552
|
+
await Promise.all(
|
|
3553
|
+
entriesToDelete.flatMap(({ entry }) => [
|
|
3554
|
+
driver.delete(buildHistoryKey(entry.location)),
|
|
3555
|
+
driver.delete(buildEntryMetadataKey(entry.id))
|
|
3556
|
+
])
|
|
3557
|
+
);
|
|
3558
|
+
for (const { key, entry } of entriesToDelete) {
|
|
3559
|
+
storage.history.entries.delete(key);
|
|
3560
|
+
storage.entryMetadata.delete(entry.id);
|
|
3561
|
+
}
|
|
3562
|
+
storage.output = void 0;
|
|
3563
|
+
storage.flushedOutput = void 0;
|
|
3564
|
+
storage.error = void 0;
|
|
3565
|
+
storage.flushedError = void 0;
|
|
3566
|
+
storage.state = "sleeping";
|
|
3567
|
+
storage.flushedState = "sleeping";
|
|
3568
|
+
await Promise.all([
|
|
3569
|
+
driver.delete(buildWorkflowOutputKey()),
|
|
3570
|
+
driver.delete(buildWorkflowErrorKey()),
|
|
3571
|
+
driver.set(buildWorkflowStateKey(), serializeWorkflowState("sleeping"))
|
|
3572
|
+
]);
|
|
3573
|
+
if ((options == null ? void 0 : options.scheduleAlarm) ?? true) {
|
|
3574
|
+
await driver.setAlarm(workflowId, Date.now());
|
|
3575
|
+
}
|
|
3576
|
+
return createHistorySnapshot(storage);
|
|
3577
|
+
}
|
|
3578
|
+
function findReplayBoundaryEntry(entries, target) {
|
|
3579
|
+
let boundary = target;
|
|
3580
|
+
let boundaryDepth = -1;
|
|
3581
|
+
for (const candidate of entries) {
|
|
3582
|
+
if (candidate.entry.kind.type !== "loop") {
|
|
3583
|
+
continue;
|
|
3584
|
+
}
|
|
3585
|
+
if (candidate.entry.location.length >= target.entry.location.length || !isLocationPrefix(candidate.entry.location, target.entry.location)) {
|
|
3586
|
+
continue;
|
|
3587
|
+
}
|
|
3588
|
+
if (candidate.entry.location.length > boundaryDepth) {
|
|
3589
|
+
boundary = candidate;
|
|
3590
|
+
boundaryDepth = candidate.entry.location.length;
|
|
3591
|
+
}
|
|
3592
|
+
}
|
|
3593
|
+
return boundary;
|
|
3594
|
+
}
|
|
3504
3595
|
async function executeWorkflow(workflowId, workflowFn, input, driver, messageDriver, abortController, onHistoryUpdated, onError, logger) {
|
|
3505
3596
|
var _a;
|
|
3506
3597
|
const storage = await loadStorage(driver);
|
|
@@ -3711,6 +3802,7 @@ export {
|
|
|
3711
3802
|
DEFAULT_STEP_TIMEOUT,
|
|
3712
3803
|
WorkflowContextImpl,
|
|
3713
3804
|
Loop,
|
|
3714
|
-
runWorkflow
|
|
3805
|
+
runWorkflow,
|
|
3806
|
+
replayWorkflowFromStep
|
|
3715
3807
|
};
|
|
3716
|
-
//# sourceMappingURL=chunk-
|
|
3808
|
+
//# sourceMappingURL=chunk-4ME2JBMC.js.map
|