@rivetkit/workflow-engine 0.0.0-main.72cbc7c → 0.0.0-main.78336a1
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-SFJQFMCW.cjs → chunk-32422MOM.cjs} +221 -93
- package/dist/tsup/chunk-32422MOM.cjs.map +1 -0
- package/dist/tsup/{chunk-CIDHCIH7.js → chunk-TVRZA5O5.js} +221 -93
- package/dist/tsup/chunk-TVRZA5O5.js.map +1 -0
- package/dist/tsup/index.cjs +2 -2
- package/dist/tsup/index.cjs.map +1 -1
- package/dist/tsup/index.d.cts +50 -13
- package/dist/tsup/index.d.ts +50 -13
- 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 +1 -0
- package/dist/tsup/testing.d.ts +1 -0
- package/dist/tsup/testing.js +7 -1
- package/dist/tsup/testing.js.map +1 -1
- package/package.json +6 -1
- package/schemas/serde.ts +17 -3
- package/schemas/v1.bare +10 -1
- package/schemas/versioned.ts +1 -0
- package/src/context.ts +140 -49
- package/src/driver.ts +12 -0
- package/src/index.ts +41 -21
- package/src/location.ts +1 -1
- package/src/storage.ts +50 -16
- package/src/testing.ts +7 -0
- package/src/types.ts +20 -3
- package/dist/tsup/chunk-CIDHCIH7.js.map +0 -1
- package/dist/tsup/chunk-SFJQFMCW.cjs.map +0 -1
package/src/storage.ts
CHANGED
|
@@ -43,6 +43,9 @@ import type {
|
|
|
43
43
|
export const MAX_KV_BATCH_ENTRIES = 128;
|
|
44
44
|
export const MAX_KV_BATCH_PAYLOAD_BYTES = 976 * 1024;
|
|
45
45
|
|
|
46
|
+
/** Max delete ops (one transaction/permit each) run at once, under the 128-permit cap. */
|
|
47
|
+
export const MAX_CONCURRENT_DELETES = 64;
|
|
48
|
+
|
|
46
49
|
/**
|
|
47
50
|
* Create an empty storage instance.
|
|
48
51
|
*/
|
|
@@ -318,26 +321,20 @@ export async function flush(
|
|
|
318
321
|
}
|
|
319
322
|
|
|
320
323
|
if (writes.length > 0) {
|
|
321
|
-
|
|
322
|
-
await driver.batch(
|
|
324
|
+
if (driver.atomicBatch) {
|
|
325
|
+
await driver.batch(writes);
|
|
326
|
+
} else {
|
|
327
|
+
for (const chunk of splitBatchWrites(writes)) {
|
|
328
|
+
await driver.batch(chunk);
|
|
329
|
+
}
|
|
323
330
|
}
|
|
324
331
|
}
|
|
325
332
|
|
|
326
333
|
// Apply pending deletions after the batch write. These are collected
|
|
327
334
|
// by collectLoopPruning so pruning happens alongside the state write.
|
|
328
335
|
if (pendingDeletions) {
|
|
329
|
-
const
|
|
330
|
-
|
|
331
|
-
deleteOps.push(driver.deletePrefix(prefix));
|
|
332
|
-
}
|
|
333
|
-
for (const range of pendingDeletions.ranges) {
|
|
334
|
-
deleteOps.push(driver.deleteRange(range.start, range.end));
|
|
335
|
-
}
|
|
336
|
-
for (const key of pendingDeletions.keys) {
|
|
337
|
-
deleteOps.push(driver.delete(key));
|
|
338
|
-
}
|
|
339
|
-
if (deleteOps.length > 0) {
|
|
340
|
-
await Promise.all(deleteOps);
|
|
336
|
+
const didChange = await runDeletes(driver, pendingDeletions);
|
|
337
|
+
if (didChange) {
|
|
341
338
|
historyUpdated = true;
|
|
342
339
|
}
|
|
343
340
|
}
|
|
@@ -393,6 +390,44 @@ function splitBatchWrites(writes: KVWrite[]): KVWrite[][] {
|
|
|
393
390
|
return chunks;
|
|
394
391
|
}
|
|
395
392
|
|
|
393
|
+
/**
|
|
394
|
+
* Split delete keys into batches within one KV transaction (MAX_KV_BATCH_ENTRIES).
|
|
395
|
+
*/
|
|
396
|
+
function splitBatchDeletes(keys: Uint8Array[]): Uint8Array[][] {
|
|
397
|
+
const chunks: Uint8Array[][] = [];
|
|
398
|
+
for (let i = 0; i < keys.length; i += MAX_KV_BATCH_ENTRIES) {
|
|
399
|
+
chunks.push(keys.slice(i, i + MAX_KV_BATCH_ENTRIES));
|
|
400
|
+
}
|
|
401
|
+
return chunks;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Apply deletions concurrently in bounded rounds; returns whether anything was deleted.
|
|
406
|
+
*/
|
|
407
|
+
async function runDeletes(
|
|
408
|
+
driver: EngineDriver,
|
|
409
|
+
deletions: PendingDeletions,
|
|
410
|
+
): Promise<boolean> {
|
|
411
|
+
const ops = [
|
|
412
|
+
...deletions.prefixes.map((prefix) => () => driver.deletePrefix(prefix)),
|
|
413
|
+
...deletions.ranges.map(
|
|
414
|
+
(range) => () => driver.deleteRange(range.start, range.end),
|
|
415
|
+
),
|
|
416
|
+
...splitBatchDeletes(deletions.keys).map(
|
|
417
|
+
(chunk) => () => driver.batchDelete(chunk),
|
|
418
|
+
),
|
|
419
|
+
];
|
|
420
|
+
if (ops.length === 0) {
|
|
421
|
+
return false;
|
|
422
|
+
}
|
|
423
|
+
for (let i = 0; i < ops.length; i += MAX_CONCURRENT_DELETES) {
|
|
424
|
+
await Promise.all(
|
|
425
|
+
ops.slice(i, i + MAX_CONCURRENT_DELETES).map((op) => op()),
|
|
426
|
+
);
|
|
427
|
+
}
|
|
428
|
+
return true;
|
|
429
|
+
}
|
|
430
|
+
|
|
396
431
|
/**
|
|
397
432
|
* Delete entries with a given location prefix (used for loop forgetting).
|
|
398
433
|
* Also cleans up associated metadata from both memory and driver.
|
|
@@ -406,8 +441,7 @@ export async function deleteEntriesWithPrefix(
|
|
|
406
441
|
const deletions = collectDeletionsForPrefix(storage, prefixLocation);
|
|
407
442
|
|
|
408
443
|
// Apply deletions to driver
|
|
409
|
-
await driver
|
|
410
|
-
await Promise.all(deletions.keys.map((key) => driver.delete(key)));
|
|
444
|
+
await runDeletes(driver, deletions);
|
|
411
445
|
|
|
412
446
|
if (deletions.keys.length > 0 && onHistoryUpdated) {
|
|
413
447
|
onHistoryUpdated();
|
package/src/testing.ts
CHANGED
|
@@ -173,6 +173,13 @@ export class InMemoryDriver implements EngineDriver {
|
|
|
173
173
|
this.kv.delete(keyToHex(key));
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
+
async batchDelete(keys: Uint8Array[]): Promise<void> {
|
|
177
|
+
await sleep(this.latency);
|
|
178
|
+
for (const key of keys) {
|
|
179
|
+
this.kv.delete(keyToHex(key));
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
176
183
|
async deletePrefix(prefix: Uint8Array): Promise<void> {
|
|
177
184
|
await sleep(this.latency);
|
|
178
185
|
for (const [hexKey, entry] of this.kv) {
|
package/src/types.ts
CHANGED
|
@@ -135,6 +135,17 @@ export interface RemovedEntry {
|
|
|
135
135
|
originalName?: string;
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
+
/**
|
|
139
|
+
* Version check entry data - records which version of a code path this
|
|
140
|
+
* workflow instance is pinned to at a given location.
|
|
141
|
+
*/
|
|
142
|
+
export interface VersionCheckEntry {
|
|
143
|
+
/** The version this instance resolved to at this location. */
|
|
144
|
+
resolved: number;
|
|
145
|
+
/** The `latest` value seen when this entry was first resolved (diagnostics). */
|
|
146
|
+
latest: number;
|
|
147
|
+
}
|
|
148
|
+
|
|
138
149
|
/**
|
|
139
150
|
* All possible entry kind types.
|
|
140
151
|
*/
|
|
@@ -146,7 +157,8 @@ export type EntryKindType =
|
|
|
146
157
|
| "rollback_checkpoint"
|
|
147
158
|
| "join"
|
|
148
159
|
| "race"
|
|
149
|
-
| "removed"
|
|
160
|
+
| "removed"
|
|
161
|
+
| "version_check";
|
|
150
162
|
|
|
151
163
|
/**
|
|
152
164
|
* Type-specific entry data.
|
|
@@ -159,7 +171,8 @@ export type EntryKind =
|
|
|
159
171
|
| { type: "rollback_checkpoint"; data: RollbackCheckpointEntry }
|
|
160
172
|
| { type: "join"; data: JoinEntry }
|
|
161
173
|
| { type: "race"; data: RaceEntry }
|
|
162
|
-
| { type: "removed"; data: RemovedEntry }
|
|
174
|
+
| { type: "removed"; data: RemovedEntry }
|
|
175
|
+
| { type: "version_check"; data: VersionCheckEntry };
|
|
163
176
|
|
|
164
177
|
/**
|
|
165
178
|
* An entry in the workflow history.
|
|
@@ -399,6 +412,8 @@ export interface StepConfig<T> {
|
|
|
399
412
|
retryBackoffMax?: number;
|
|
400
413
|
/** Timeout in ms for step execution (default: 30000). Set to 0 to disable. */
|
|
401
414
|
timeout?: number;
|
|
415
|
+
/** If true, step timeouts retry like any other error instead of failing immediately as critical. Default: false. */
|
|
416
|
+
retryOnTimeout?: boolean;
|
|
402
417
|
}
|
|
403
418
|
|
|
404
419
|
export type TryStepCatchKind =
|
|
@@ -455,7 +470,7 @@ export type LoopResult<S, T> =
|
|
|
455
470
|
* `Loop.continue(undefined)`.
|
|
456
471
|
*/
|
|
457
472
|
export type LoopIterationResult<S, T> = Promise<
|
|
458
|
-
LoopResult<S, T> | (S extends undefined ?
|
|
473
|
+
LoopResult<S, T> | (S extends undefined ? undefined : never)
|
|
459
474
|
>;
|
|
460
475
|
|
|
461
476
|
/**
|
|
@@ -537,6 +552,8 @@ export interface WorkflowContextInterface {
|
|
|
537
552
|
|
|
538
553
|
removed(name: string, originalType: EntryKindType): Promise<void>;
|
|
539
554
|
|
|
555
|
+
getVersion(name: string, latest: number): Promise<number>;
|
|
556
|
+
|
|
540
557
|
isEvicted(): boolean;
|
|
541
558
|
}
|
|
542
559
|
|