@lostgradient/weft 0.7.0 → 0.9.0
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/README.md +9 -3
- package/dist/cli/generated/operation-client.generated.d.ts +1 -0
- package/dist/cli-main.js +78 -78
- package/dist/core/context/activity-retry-state.d.ts +6 -5
- package/dist/core/context/activity-retry-state.js +31 -21
- package/dist/core/context/durable-activity.d.ts +117 -0
- package/dist/core/context/durable-activity.js +79 -0
- package/dist/core/context/durable-operations.js +1 -1
- package/dist/core/context/index.d.ts +1 -0
- package/dist/core/context/index.js +2 -0
- package/dist/core/context/operation-request.d.ts +17 -0
- package/dist/core/context/parallel-operations.js +1 -0
- package/dist/core/context/run-operation-cached-request.d.ts +8 -0
- package/dist/core/context/run-operation-cached-request.js +59 -0
- package/dist/core/context/run-operation.d.ts +23 -5
- package/dist/core/context/run-operation.js +63 -47
- package/dist/core/context/speculative-child.js +1 -0
- package/dist/core/context/types.d.ts +1 -0
- package/dist/core/engine/activity-heartbeat-tracking.d.ts +8 -17
- package/dist/core/engine/activity-heartbeat-tracking.js +12 -2
- package/dist/core/engine/activity-reconciliation.d.ts +1 -0
- package/dist/core/engine/activity-reconciliation.js +7 -2
- package/dist/core/engine/anonymous-signal-sequence.js +6 -6
- package/dist/core/engine/async-activity-completion.d.ts +5 -7
- package/dist/core/engine/async-activity-completion.js +13 -9
- package/dist/core/engine/bulk-operations-purge.js +2 -1
- package/dist/core/engine/bulk-operations.js +18 -36
- package/dist/core/engine/callback-checkpoint-persistence.d.ts +3 -0
- package/dist/core/engine/callback-checkpoint-persistence.js +25 -0
- package/dist/core/engine/callback-creators-bundles.js +5 -2
- package/dist/core/engine/checkpoint-io.d.ts +4 -1
- package/dist/core/engine/checkpoint-io.js +19 -10
- package/dist/core/engine/completed-review-storage.d.ts +2 -1
- package/dist/core/engine/completed-review-storage.js +4 -3
- package/dist/core/engine/disposal.js +1 -0
- package/dist/core/engine/engine-internal-types.d.ts +1 -0
- package/dist/core/engine/index.d.ts +31 -0
- package/dist/core/engine/index.js +19 -10
- package/dist/core/engine/inline-launch-queue.js +1 -1
- package/dist/core/engine/internals.d.ts +25 -2
- package/dist/core/engine/lease-manager.js +2 -2
- package/dist/core/engine/lifecycle/fork-helpers.js +1 -0
- package/dist/core/engine/lifecycle/resume.js +6 -0
- package/dist/core/engine/lifecycle/start-exec.d.ts +2 -2
- package/dist/core/engine/lifecycle/start-exec.js +6 -4
- package/dist/core/engine/lifecycle/start.js +1 -0
- package/dist/core/engine/lifecycle/transition.js +6 -0
- package/dist/core/engine/memo-durable-activity.d.ts +11 -0
- package/dist/core/engine/memo-durable-activity.js +282 -0
- package/dist/core/engine/operations-activity.d.ts +6 -2
- package/dist/core/engine/operations-activity.js +24 -10
- package/dist/core/engine/operations-data.d.ts +4 -1
- package/dist/core/engine/operations-data.js +3 -3
- package/dist/core/engine/operations-time.d.ts +2 -2
- package/dist/core/engine/operations-time.js +40 -6
- package/dist/core/engine/reviews.js +7 -4
- package/dist/core/engine/schedule-timer.js +2 -0
- package/dist/core/engine/schedules.js +3 -0
- package/dist/core/engine/storage-io.js +1 -1
- package/dist/core/engine/termination/cleanup.js +15 -13
- package/dist/core/engine/termination/finalizer-activity.d.ts +1 -1
- package/dist/core/engine/termination/finalizer-activity.js +5 -1
- package/dist/core/engine/termination/finalizer.js +1 -1
- package/dist/core/engine/validation/schedule-options.d.ts +9 -0
- package/dist/core/engine/validation/schedule-options.js +59 -0
- package/dist/core/engine/validation/schedule.d.ts +3 -8
- package/dist/core/engine/validation/schedule.js +40 -56
- package/dist/core/engine/validation.js +1 -0
- package/dist/core/execution-strategy.d.ts +1 -0
- package/dist/core/inline-execution-strategy.context-options.d.ts +1 -0
- package/dist/core/inline-execution-strategy.context-options.js +3 -0
- package/dist/core/json.js +1 -1
- package/dist/core/types/activity.d.ts +11 -0
- package/dist/core/types/checkpoint.d.ts +1 -0
- package/dist/core/types/schedules.d.ts +10 -0
- package/dist/core/types/state.d.ts +6 -0
- package/dist/core/types/workflow-context.d.ts +13 -0
- package/dist/core/weft-error.d.ts +1 -1
- package/dist/core/weft-error.js +2 -0
- package/dist/core/worker-execution-strategy.d.ts +1 -0
- package/dist/core/worker-inbound-message.d.ts +1 -0
- package/dist/core/worker-inbound-message.js +3 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +6 -0
- package/dist/json-schema.js +2 -2
- package/dist/mcp/cli.js +32 -32
- package/dist/observability/index.js +2 -2
- package/dist/runtime/portable.d.ts +1 -1
- package/dist/server/handler.js +27 -27
- package/dist/server/index.d.ts +2 -0
- package/dist/server/index.js +32 -32
- package/dist/server/operations/create-schedule.d.ts +2 -0
- package/dist/server/operations/create-schedule.js +13 -2
- package/dist/server/rest-binding.d.ts +1 -1
- package/dist/server/runtime/task-dispatch.js +6 -0
- package/dist/server/runtime/task-polling.js +9 -1
- package/dist/server/runtime/task-reconciliation.js +2 -1
- package/dist/server/runtime/websocket-worker.js +7 -2
- package/dist/server/serve-internals.d.ts +28 -0
- package/dist/server/serve-internals.js +4 -2
- package/dist/server/task-queue-types.d.ts +2 -0
- package/dist/server/task-state.d.ts +4 -0
- package/dist/service-worker/index.d.ts +15 -14
- package/dist/service-worker/index.js +28 -28
- package/dist/service-worker/scheduler.d.ts +41 -1
- package/dist/service-worker/setup.d.ts +18 -1
- package/dist/service-worker/setup.js +7 -4
- package/dist/storage/auto.d.ts +36 -18
- package/dist/storage/auto.js +1 -1
- package/dist/storage/compressed-storage.js +1 -1
- package/dist/storage/indexeddb.d.ts +6 -1
- package/dist/storage/indexeddb.js +1 -1
- package/dist/storage/interface.js +1 -1
- package/dist/storage/lmdb.js +1 -1
- package/dist/storage/memory.js +1 -1
- package/dist/storage/neon.js +1 -1
- package/dist/storage/resolve.js +1 -1
- package/dist/storage/scoped-storage.js +1 -1
- package/dist/storage/testing.js +1 -1
- package/dist/storage/turso.js +1 -1
- package/dist/storage/typed-storage.d.ts +1 -1
- package/dist/storage/typed-storage.js +1 -1
- package/dist/storage/web-extension.d.ts +1 -1
- package/dist/storage/web-extension.js +1 -1
- package/dist/testing/index.js +32 -32
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/worker/execute-with-interceptors.d.ts +9 -3
- package/dist/worker/execute-with-interceptors.js +14 -2
- package/dist/worker/long-poll.d.ts +2 -1
- package/dist/worker/long-poll.js +1 -1
- package/dist/worker/protocol-messages.d.ts +2 -0
- package/dist/worker/protocol-schemas.d.ts +8 -0
- package/dist/worker/protocol-schemas.js +1 -0
- package/dist/worker/protocol.js +1 -1
- package/dist/worker/remote-activity-context.d.ts +2 -0
- package/dist/workers/activity-runner.d.ts +2 -0
- package/dist/workers/activity-runner.js +9 -1
- package/dist/workers/workflow-runner.d.ts +2 -1
- package/dist/workers/workflow-runner.js +1 -0
- package/package.json +1 -1
|
@@ -6,6 +6,9 @@ type PendingTimelineEntryValue = {
|
|
|
6
6
|
startedAt: number;
|
|
7
7
|
entry: WorkflowTimelineEntry;
|
|
8
8
|
};
|
|
9
|
+
export type PersistCheckpointOptions = {
|
|
10
|
+
timeline?: 'record-operation' | 'preserve-pending';
|
|
11
|
+
};
|
|
9
12
|
type PersistCheckpointCallbacks = {
|
|
10
13
|
appendTimelineBatchOperations: (workflowId: string, operation: ContextOperationRequest, step: number, timestamp: number, operations: BatchOperation[]) => PendingTimelineEntryValue;
|
|
11
14
|
swallowPromiseRejection: (promise: Promise<void>) => void;
|
|
@@ -26,7 +29,7 @@ type DevelopmentCheckpointCallbacks = {
|
|
|
26
29
|
};
|
|
27
30
|
export declare function appendTimelineBatchOperations(internals: EngineInternals, workflowId: string, operation: ContextOperationRequest, step: number, timestamp: number, operations: BatchOperation[]): PendingTimelineEntryValue;
|
|
28
31
|
/** Persist a workflow checkpoint, history entry, timeline record, and event log record. */
|
|
29
|
-
export declare function persistCheckpoint(internals: EngineInternals, workflowId: string, operation: ContextOperationRequest, workerCheckpointBytes: ArrayBuffer | undefined, callbacks: PersistCheckpointCallbacks): Promise<void>;
|
|
32
|
+
export declare function persistCheckpoint(internals: EngineInternals, workflowId: string, operation: ContextOperationRequest, workerCheckpointBytes: ArrayBuffer | undefined, callbacks: PersistCheckpointCallbacks, options?: PersistCheckpointOptions): Promise<void>;
|
|
30
33
|
/** Delete the single checkpoint history entry that overflows the retention limit. */
|
|
31
34
|
export declare function pruneCheckpointHistory(internals: EngineInternals, workflowId: string, currentStep: number): Promise<void>;
|
|
32
35
|
/** Validate checkpoint serialization in development mode and dispatch warnings. */
|
|
@@ -60,13 +60,13 @@ export function appendTimelineBatchOperations(internals, workflowId, operation,
|
|
|
60
60
|
entry
|
|
61
61
|
};
|
|
62
62
|
}
|
|
63
|
-
export async function persistCheckpoint(internals, workflowId, operation, workerCheckpointBytes, callbacks) {
|
|
63
|
+
export async function persistCheckpoint(internals, workflowId, operation, workerCheckpointBytes, callbacks, options = {}) {
|
|
64
64
|
if (internals.inlineStrategy?.getContext(workflowId))
|
|
65
|
-
await persistInlineCheckpoint(internals, workflowId, operation, callbacks);
|
|
65
|
+
await persistInlineCheckpoint(internals, workflowId, operation, callbacks, options);
|
|
66
66
|
else if (workerCheckpointBytes && workerCheckpointBytes.byteLength > 0)
|
|
67
|
-
await persistWorkerCheckpoint(internals, workflowId, operation, workerCheckpointBytes, callbacks);
|
|
67
|
+
await persistWorkerCheckpoint(internals, workflowId, operation, workerCheckpointBytes, callbacks, options);
|
|
68
68
|
}
|
|
69
|
-
async function persistInlineCheckpoint(internals, workflowId, operation, callbacks) {
|
|
69
|
+
async function persistInlineCheckpoint(internals, workflowId, operation, callbacks, options) {
|
|
70
70
|
const current = internals.checkpoints.get(workflowId), context = internals.inlineStrategy?.getContext(workflowId);
|
|
71
71
|
if (!current || !context)
|
|
72
72
|
return;
|
|
@@ -76,13 +76,13 @@ async function persistInlineCheckpoint(internals, workflowId, operation, callbac
|
|
|
76
76
|
...pendingAttributeChanges !== void 0 ? { searchAttributes: pendingAttributeChanges } : {}
|
|
77
77
|
}), pruned = pruneCheckpointReplayState(advanced, resolvePendingOperationStep(operation, context.stepIndex)), commit = createCheckpointCommit(internals, workflowId, pruned.checkpoint, serializeCheckpoint(attachTransientCheckpointReplayPayload(pruned.checkpoint, pruned.replayPayload)), pruned.replayPayload);
|
|
78
78
|
appendAttributeOperations(workflowId, commit, previousAttributes, pendingAttributeChanges, hasPendingAttributeChangesValue, callbacks);
|
|
79
|
-
await commitCheckpoint(internals, workflowId, operation, commit, callbacks);
|
|
79
|
+
await commitCheckpoint(internals, workflowId, operation, commit, callbacks, options);
|
|
80
80
|
if (hasPendingAttributeChangesValue)
|
|
81
81
|
callbacks.dispatchEvent(new AttributesChangedEvent(workflowId, { ...pendingAttributeChanges }));
|
|
82
82
|
}
|
|
83
|
-
async function persistWorkerCheckpoint(internals, workflowId, operation, workerCheckpointBytes, callbacks) {
|
|
83
|
+
async function persistWorkerCheckpoint(internals, workflowId, operation, workerCheckpointBytes, callbacks, options) {
|
|
84
84
|
const serialized = new Uint8Array(workerCheckpointBytes), checkpoint = deserializeCheckpoint(serialized), workerReplayPayload = readCheckpointReplayPayload(checkpoint), pruned = pruneCheckpointReplayState(checkpoint, resolvePendingOperationStep(operation, checkpoint.step)), replayPayload = mergeCheckpointReplayPayloads(workerReplayPayload, pruned.replayPayload), prunedSerialized = serializeCheckpoint(attachTransientCheckpointReplayPayload(pruned.checkpoint, replayPayload));
|
|
85
|
-
await commitCheckpoint(internals, workflowId, operation, createCheckpointCommit(internals, workflowId, pruned.checkpoint, prunedSerialized, replayPayload), callbacks);
|
|
85
|
+
await commitCheckpoint(internals, workflowId, operation, createCheckpointCommit(internals, workflowId, pruned.checkpoint, prunedSerialized, replayPayload), callbacks, options);
|
|
86
86
|
}
|
|
87
87
|
function createCheckpointCommit(internals, workflowId, checkpoint, serialized, replayPayload) {
|
|
88
88
|
const operations = [
|
|
@@ -116,9 +116,9 @@ function appendAttributeOperations(workflowId, commit, previousAttributes, pendi
|
|
|
116
116
|
});
|
|
117
117
|
commit.operations.push(...buildIndexOperations(workflowId, previousAttributes, commit.checkpoint.searchAttributes));
|
|
118
118
|
}
|
|
119
|
-
async function commitCheckpoint(internals, workflowId, operation, commit, callbacks) {
|
|
119
|
+
async function commitCheckpoint(internals, workflowId, operation, commit, callbacks, options) {
|
|
120
120
|
dispatchCheckpointSizeWarning(internals, workflowId, commit, callbacks);
|
|
121
|
-
const nextPendingTimelineEntry = callbacks.appendTimelineBatchOperations(workflowId, operation, commit.step, commit.timestamp, commit.operations), { newHead, timestamp } = appendCheckpointEventLog(internals, workflowId, commit), retentionWindow = internals.options.historyPolicy.retentionWindow, compaction = retentionWindow === null ? null : await appendCompactionOperations(internals.storage, workflowId, newHead.sequence, retentionWindow, commit.operations), pendingSideEffects = takePendingAtomicWorkflowCommitSideEffects(internals, workflowId);
|
|
121
|
+
const nextPendingTimelineEntry = options.timeline === "preserve-pending" ? preservePendingTimelineEntry(internals, workflowId, commit.operations) : callbacks.appendTimelineBatchOperations(workflowId, operation, commit.step, commit.timestamp, commit.operations), { newHead, timestamp } = appendCheckpointEventLog(internals, workflowId, commit), retentionWindow = internals.options.historyPolicy.retentionWindow, compaction = retentionWindow === null ? null : await appendCompactionOperations(internals.storage, workflowId, newHead.sequence, retentionWindow, commit.operations), pendingSideEffects = takePendingAtomicWorkflowCommitSideEffects(internals, workflowId);
|
|
122
122
|
if (pendingSideEffects !== void 0)
|
|
123
123
|
commit.operations.push(...pendingSideEffects.operations);
|
|
124
124
|
const storageSupportsConditionalBatch = internals.storage.capabilities().conditionalBatch, sideEffectConditions = checkpointSideEffectConditions(pendingSideEffects, storageSupportsConditionalBatch), conditions = buildCheckpointCommitConditions(workflowId, commit, storageSupportsConditionalBatch, sideEffectConditions);
|
|
@@ -129,7 +129,10 @@ async function commitCheckpoint(internals, workflowId, operation, commit, callba
|
|
|
129
129
|
clearPendingAtomicWorkflowCommitSideEffects(internals, workflowId);
|
|
130
130
|
if (commit.expectedSerialized !== void 0)
|
|
131
131
|
rememberCommittedCheckpointBytes(internals, workflowId, commit.serialized);
|
|
132
|
-
|
|
132
|
+
if (nextPendingTimelineEntry === void 0)
|
|
133
|
+
internals.pendingTimelineEntries.delete(workflowId);
|
|
134
|
+
else
|
|
135
|
+
internals.pendingTimelineEntries.set(workflowId, nextPendingTimelineEntry);
|
|
133
136
|
internals.checkpoints.set(workflowId, commit.checkpoint);
|
|
134
137
|
internals.eventLogHeads.set(workflowId, newHead);
|
|
135
138
|
if (compaction !== null)
|
|
@@ -146,6 +149,12 @@ async function commitCheckpoint(internals, workflowId, operation, commit, callba
|
|
|
146
149
|
if (historyEventLimitBreached(internals, newHead.sequence))
|
|
147
150
|
await callbacks.enforceHistoryCircuitBreaker(workflowId);
|
|
148
151
|
}
|
|
152
|
+
function preservePendingTimelineEntry(internals, workflowId, operations) {
|
|
153
|
+
const pendingTimelineOperation = buildPendingTimelineOperation(internals, workflowId);
|
|
154
|
+
if (pendingTimelineOperation)
|
|
155
|
+
operations.push(pendingTimelineOperation);
|
|
156
|
+
return internals.pendingTimelineEntries.get(workflowId);
|
|
157
|
+
}
|
|
149
158
|
function checkpointSideEffectConditions(pendingSideEffects, storageSupportsConditionalBatch) {
|
|
150
159
|
if (!storageSupportsConditionalBatch)
|
|
151
160
|
return [];
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Storage } from '../../storage/interface.ts';
|
|
2
2
|
import type { HumanReviewResult, ReviewRequest } from '../review/index.ts';
|
|
3
3
|
import type { CompletedReviewEntry, ReviewListFilter } from '../types.ts';
|
|
4
|
+
import type { EngineInternals } from './internals.ts';
|
|
4
5
|
type ReviewListFilterableEntry = {
|
|
5
6
|
workflowId?: string;
|
|
6
7
|
reviewType?: string;
|
|
@@ -9,6 +10,6 @@ export declare function matchesReviewListFilter(review: ReviewListFilterableEntr
|
|
|
9
10
|
export declare function completedReviewStoragePrefix(workflowId?: string): string;
|
|
10
11
|
export declare function completedReviewStorageKey(workflowId: string, reviewId: string): string;
|
|
11
12
|
export declare function listCompletedReviewsFromStorage(storage: Storage, filter: ReviewListFilter): Promise<CompletedReviewEntry[]>;
|
|
12
|
-
export declare function persistCompletedReviewRecord(
|
|
13
|
+
export declare function persistCompletedReviewRecord(internals: EngineInternals, reviewKey: string, reviewData: ReviewRequest, decisionResult: HumanReviewResult): Promise<void>;
|
|
13
14
|
export declare function deleteCompletedReviewsForWorkflow(storage: Storage, workflowId: string): Promise<void>;
|
|
14
15
|
export {};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { encodeStorageKeyComponent } from "../../storage/interface.js";
|
|
2
2
|
import { encode } from "../codec.js";
|
|
3
|
+
import { commitFencedEngineWrite } from "./fenced-write.js";
|
|
3
4
|
import { parseCompletedReviewEntry, toCompletedReviewEntry } from "./review-list-entries.js";
|
|
4
5
|
export function matchesReviewListFilter(review, filter) {
|
|
5
6
|
if (filter.workflowId !== void 0 && review.workflowId !== filter.workflowId)
|
|
@@ -32,16 +33,16 @@ export async function listCompletedReviewsFromStorage(storage, filter) {
|
|
|
32
33
|
await appendCompletedReviews(reviews, storage.scan("review-decision:"), filter, (key) => scopedPrefix === null || !key.startsWith(scopedPrefix));
|
|
33
34
|
return reviews;
|
|
34
35
|
}
|
|
35
|
-
export async function persistCompletedReviewRecord(
|
|
36
|
+
export async function persistCompletedReviewRecord(internals, reviewKey, reviewData, decisionResult) {
|
|
36
37
|
const completedReview = toCompletedReviewEntry(reviewData, decisionResult);
|
|
37
|
-
await
|
|
38
|
+
await commitFencedEngineWrite(internals, [
|
|
38
39
|
{
|
|
39
40
|
type: "put",
|
|
40
41
|
key: completedReviewStorageKey(reviewData.workflowId, reviewData.reviewId),
|
|
41
42
|
value: encode(completedReview)
|
|
42
43
|
},
|
|
43
44
|
{ type: "delete", key: reviewKey }
|
|
44
|
-
]);
|
|
45
|
+
], [], () => Error(`Completed review commit for review "${reviewData.reviewId}" lost its precondition.`));
|
|
45
46
|
}
|
|
46
47
|
export async function deleteCompletedReviewsForWorkflow(storage, workflowId) {
|
|
47
48
|
const completedPrefix = completedReviewStoragePrefix(workflowId), deleteOperations = [];
|
|
@@ -46,6 +46,7 @@ export function disposeEngine(internals) {
|
|
|
46
46
|
internals.pendingWebhooks.clear();
|
|
47
47
|
internals.sleepResolvers.clear();
|
|
48
48
|
internals.sleepResolversByWorkflow.clear();
|
|
49
|
+
internals.sleepTimersFiredWithoutResolver.clear();
|
|
49
50
|
internals.checkpoints.clear();
|
|
50
51
|
internals.pendingExecutionStateOwnerId = void 0;
|
|
51
52
|
internals.workflowNestingDepths.clear();
|
|
@@ -36,6 +36,25 @@ export { assertCompatiblePersistedDataVersion };
|
|
|
36
36
|
export declare const ENGINE_PARKED_WORKFLOW_COUNT_FOR_TESTING: unique symbol;
|
|
37
37
|
export declare const ENGINE_SIGNAL_WAITER_COUNT_FOR_TESTING: unique symbol;
|
|
38
38
|
export declare const ENGINE_SLEEP_RESOLVER_COUNT_FOR_TESTING: unique symbol;
|
|
39
|
+
/**
|
|
40
|
+
* The `name` of the `process` warning emitted when a lease-owning engine is
|
|
41
|
+
* disposed through the synchronous `[Symbol.dispose]()` path. Sync disposal can
|
|
42
|
+
* only fire the lease release in the background; use `await engine.shutdown()`,
|
|
43
|
+
* `await using`, or `await engine[Symbol.asyncDispose]()` when prompt rolling
|
|
44
|
+
* deploy handoff matters.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* import { ENGINE_LEASE_SYNCHRONOUS_DISPOSE_WARNING_NAME } from '@lostgradient/weft';
|
|
49
|
+
*
|
|
50
|
+
* process.on('warning', (warning) => {
|
|
51
|
+
* if (warning.name === ENGINE_LEASE_SYNCHRONOUS_DISPOSE_WARNING_NAME) {
|
|
52
|
+
* // Alert on shutdown paths that can make lease handoff wait for leaseTtl.
|
|
53
|
+
* }
|
|
54
|
+
* });
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export declare const ENGINE_LEASE_SYNCHRONOUS_DISPOSE_WARNING_NAME = "WeftEngineLeaseSynchronousDisposeWarning";
|
|
39
58
|
export { ENGINE_LEASE_LOST_WARNING_NAME };
|
|
40
59
|
/**
|
|
41
60
|
* Durable execution engine.
|
|
@@ -408,6 +427,18 @@ export declare class Engine<TWorkflows extends object = DefaultWorkflowRegistry,
|
|
|
408
427
|
timeout?: number;
|
|
409
428
|
idempotencyKey?: string;
|
|
410
429
|
}): Promise<CoordinatedUpdateResult>;
|
|
430
|
+
/**
|
|
431
|
+
* Awaited engine shutdown. Equivalent to
|
|
432
|
+
* `await engine[Symbol.asyncDispose]()` and useful in explicit signal handlers
|
|
433
|
+
* where `await using` syntax cannot own the process lifetime directly.
|
|
434
|
+
*
|
|
435
|
+
* Under `ownership: 'lease'`, this is the explicit prompt-handoff primitive:
|
|
436
|
+
* it drains queued inline starts, tears down in-memory write paths, and awaits
|
|
437
|
+
* lease release before resolving. Synchronous disposal remains immediate and
|
|
438
|
+
* can make the next engine wait for `leaseTtl` if the process exits before its
|
|
439
|
+
* background release completes.
|
|
440
|
+
*/
|
|
441
|
+
shutdown(): Promise<void>;
|
|
411
442
|
/**
|
|
412
443
|
* Synchronous teardown (`using engine = ...`). Pending inline launches that
|
|
413
444
|
* have not yet run are **discarded**, not executed. When you need queued
|
|
@@ -206,9 +206,19 @@ export {
|
|
|
206
206
|
shouldEmitEngineLeakWarningForTesting
|
|
207
207
|
} from "./engine-leak-warnings.js";
|
|
208
208
|
export { assertCompatiblePersistedDataVersion };
|
|
209
|
-
export const ENGINE_PARKED_WORKFLOW_COUNT_FOR_TESTING = Symbol("engineParkedWorkflowCountForTesting"), ENGINE_SIGNAL_WAITER_COUNT_FOR_TESTING = Symbol("engineSignalWaiterCountForTesting"), ENGINE_SLEEP_RESOLVER_COUNT_FOR_TESTING = Symbol("engineSleepResolverCountForTesting");
|
|
209
|
+
export const ENGINE_PARKED_WORKFLOW_COUNT_FOR_TESTING = Symbol("engineParkedWorkflowCountForTesting"), ENGINE_SIGNAL_WAITER_COUNT_FOR_TESTING = Symbol("engineSignalWaiterCountForTesting"), ENGINE_SLEEP_RESOLVER_COUNT_FOR_TESTING = Symbol("engineSleepResolverCountForTesting"), ENGINE_LEASE_SYNCHRONOUS_DISPOSE_WARNING_NAME = "WeftEngineLeaseSynchronousDisposeWarning";
|
|
210
210
|
|
|
211
211
|
export { ENGINE_LEASE_LOST_WARNING_NAME };
|
|
212
|
+
function scheduleDefinitionFromInternals(internals, definition) {
|
|
213
|
+
const workflowType = typeof definition.workflow === "string" ? definition.workflow : definition.workflow.name, definitionSpec = definition.every !== void 0 ? { every: definition.every } : { cron: definition.cron ?? "" };
|
|
214
|
+
return scheduleFromInternals(internals, workflowType, definition.input, definitionSpec, {
|
|
215
|
+
...definition.id !== void 0 && { id: definition.id },
|
|
216
|
+
...definition.description !== void 0 && { description: definition.description },
|
|
217
|
+
...definition.overlapPolicy !== void 0 && { overlap: definition.overlapPolicy },
|
|
218
|
+
...definition.backfill !== void 0 && { backfill: definition.backfill },
|
|
219
|
+
...definition.jitter !== void 0 && { jitter: definition.jitter }
|
|
220
|
+
});
|
|
221
|
+
}
|
|
212
222
|
|
|
213
223
|
export class Engine extends EventTarget {
|
|
214
224
|
static async create(options) {
|
|
@@ -267,6 +277,7 @@ export class Engine extends EventTarget {
|
|
|
267
277
|
getInternals(this).updateWaitersByWorkflow = new Map;
|
|
268
278
|
getInternals(this).sleepResolvers = new Map;
|
|
269
279
|
getInternals(this).sleepResolversByWorkflow = new Map;
|
|
280
|
+
getInternals(this).sleepTimersFiredWithoutResolver = new Map;
|
|
270
281
|
getInternals(this).interceptors = resolveEngineInterceptors(options);
|
|
271
282
|
getInternals(this).composedWorkflowInterceptor = void 0;
|
|
272
283
|
getInternals(this).composedActivityInterceptor = void 0;
|
|
@@ -599,15 +610,8 @@ export class Engine extends EventTarget {
|
|
|
599
610
|
return untagAllWorkflows(getInternals(this), filter, tags, options);
|
|
600
611
|
}
|
|
601
612
|
async schedule(typeOrDefinition, input, spec, options) {
|
|
602
|
-
if (typeof typeOrDefinition === "object")
|
|
603
|
-
|
|
604
|
-
return scheduleFromInternals(getInternals(this), workflowType, definition.input, definitionSpec, {
|
|
605
|
-
...definition.id !== void 0 && { id: definition.id },
|
|
606
|
-
...definition.overlapPolicy !== void 0 && { overlap: definition.overlapPolicy },
|
|
607
|
-
...definition.backfill !== void 0 && { backfill: definition.backfill },
|
|
608
|
-
...definition.jitter !== void 0 && { jitter: definition.jitter }
|
|
609
|
-
});
|
|
610
|
-
}
|
|
613
|
+
if (typeof typeOrDefinition === "object")
|
|
614
|
+
return scheduleDefinitionFromInternals(getInternals(this), typeOrDefinition);
|
|
611
615
|
if (spec === void 0)
|
|
612
616
|
throw Error("A cron string or schedule spec must be provided when scheduling by workflow type.");
|
|
613
617
|
return scheduleFromInternals(getInternals(this), typeOrDefinition, input, spec, options);
|
|
@@ -769,8 +773,13 @@ export class Engine extends EventTarget {
|
|
|
769
773
|
async submitCoordinatedUpdate(workflowId, name, payload, options) {
|
|
770
774
|
return submitCoordinatedUpdateFromInternals(getInternals(this), workflowId, name, payload, options, this.#createUpdateCallbacks());
|
|
771
775
|
}
|
|
776
|
+
async shutdown() {
|
|
777
|
+
return this[Symbol.asyncDispose]();
|
|
778
|
+
}
|
|
772
779
|
[Symbol.dispose]() {
|
|
773
780
|
const leaseManager = getInternals(this).leaseManager;
|
|
781
|
+
if (leaseManager !== null && leaseManager.currentEpochBytes() !== null)
|
|
782
|
+
process.emitWarning("engine ownership lease disposed synchronously; lease release is fire-and-forget, so exiting before the release completes can make the next instance wait for leaseTtl. Use await engine.shutdown(), await using, or await engine[Symbol.asyncDispose]() for prompt rolling-deploy handoff.", ENGINE_LEASE_SYNCHRONOUS_DISPOSE_WARNING_NAME);
|
|
774
783
|
disposeEngine(getInternals(this));
|
|
775
784
|
leaseManager?.release();
|
|
776
785
|
}
|
|
@@ -58,7 +58,7 @@ async function startQueuedInlineWorkflowExecution(internals, start, callbacks) {
|
|
|
58
58
|
return;
|
|
59
59
|
internals.queuedInlineWorkflowStartIds.delete(start.workflowId);
|
|
60
60
|
internals.engine.dispatchEvent(new WorkflowStartedEvent(start.workflowId, start.workflowType, start.input));
|
|
61
|
-
startWorkflowExecution(internals, start.workflowId, start.workflowType, start.input, start.checkpoint, start.nestingDepth, start.executionDeadline, start.executionStateOwnerId);
|
|
61
|
+
startWorkflowExecution(internals, start.workflowId, state.workflowExecutionToken, start.workflowType, start.input, start.checkpoint, start.nestingDepth, start.executionDeadline, start.executionStateOwnerId);
|
|
62
62
|
await callbacks.processPendingUpdatesAfterInlineAdvance(start.workflowId);
|
|
63
63
|
} finally {
|
|
64
64
|
internals.queuedInlineWorkflowStartIds.delete(start.workflowId);
|
|
@@ -31,6 +31,7 @@ import type { Scheduler } from '../scheduler.ts';
|
|
|
31
31
|
import type { Checkpoint, StartWorkflowOptions } from '../types.ts';
|
|
32
32
|
import type { UpdateCoordinator } from '../updates.ts';
|
|
33
33
|
import type { WorkflowVersionTuple } from '../workflow-version-tuple.ts';
|
|
34
|
+
import type { ActivityHeartbeatKey } from './activity-heartbeat-tracking.ts';
|
|
34
35
|
import type { PendingTimelineEntry, QueuedInlineWorkflowExecutionStart, RegistrationEntry, ResolvedOptions, TrackedWaiterKeys, WorkflowResultWaiter } from './engine-internal-types.ts';
|
|
35
36
|
import type { EngineCleanupIntervalDisposalTracker } from './engine-leak-warnings.ts';
|
|
36
37
|
import type { WorkflowHandle, WorkflowHandleEngine } from './handles.ts';
|
|
@@ -89,8 +90,30 @@ export interface EngineInternals {
|
|
|
89
90
|
conditionWaiters: Map<string, () => void>;
|
|
90
91
|
updateWaiters: Map<string, (payload: unknown) => void>;
|
|
91
92
|
updateWaitersByWorkflow: Map<string, TrackedWaiterKeys>;
|
|
92
|
-
|
|
93
|
+
/**
|
|
94
|
+
* In-process sleep resolvers keyed by `${workflowId}:${operationId}`. Each
|
|
95
|
+
* carries the run's expected `fireAt` so a fired timer only settles the sleep
|
|
96
|
+
* whose deadline it represents — a stale timer from a terminated run that
|
|
97
|
+
* reused the same deterministic operationId (its durable timer outlives
|
|
98
|
+
* terminal cleanup) is ignored rather than resolving a replacement run early.
|
|
99
|
+
*/
|
|
100
|
+
sleepResolvers: Map<string, {
|
|
101
|
+
resolve: () => void;
|
|
102
|
+
fireAt: number;
|
|
103
|
+
}>;
|
|
93
104
|
sleepResolversByWorkflow: Map<string, Set<string>>;
|
|
105
|
+
/**
|
|
106
|
+
* Per-workflow maps of `operationId` → fired timer `fireAt` for sleep timers
|
|
107
|
+
* the scheduler tick fired before the resolver was registered. Keyed by
|
|
108
|
+
* `workflowId` so per-workflow cleanup (`cleanupSleepResolvers`,
|
|
109
|
+
* `evictSleepResolversWithoutResolving`) can call `.delete(workflowId)` and
|
|
110
|
+
* sweep all markers in O(1) — including orphaned ones where the timer fired
|
|
111
|
+
* while the workflow was suspended (no `sleepResolversByWorkflow` entry) or
|
|
112
|
+
* during recovery of an already-elapsed sleep that takes the early-return
|
|
113
|
+
* path. The `fireAt` lets `processSleepOperation` ignore a marker left by a
|
|
114
|
+
* stale earlier-run timer. Cleared entirely at engine disposal.
|
|
115
|
+
*/
|
|
116
|
+
sleepTimersFiredWithoutResolver: Map<string, Map<string, number>>;
|
|
94
117
|
interceptors: Interceptor[];
|
|
95
118
|
composedWorkflowInterceptor: ComposedWorkflowInterceptor | null | undefined;
|
|
96
119
|
composedActivityInterceptor: ComposedActivityInterceptor | null | undefined;
|
|
@@ -148,7 +171,7 @@ export interface EngineInternals {
|
|
|
148
171
|
* {@link heartbeatDetails}. Inline-execution only; worker-executed activities run
|
|
149
172
|
* their function out of process and never observe this.
|
|
150
173
|
*/
|
|
151
|
-
lastHeartbeatDetailsByStep: Map<string, Map<
|
|
174
|
+
lastHeartbeatDetailsByStep: Map<string, Map<ActivityHeartbeatKey, unknown>>;
|
|
152
175
|
/**
|
|
153
176
|
* Per-run, non-serialized `services` value exposed to the workflow body as
|
|
154
177
|
* `ctx.services`. Set at `engine.start({ services })` and re-provided on
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
import { EngineLeaseAcquisitionTimeoutError, EngineLeaseCorruptedError } from "./lease-errors.js";
|
|
9
9
|
const DEFAULT_ACQUIRE_POLL_INTERVAL_MS = 1000;
|
|
10
10
|
export function createLeaseManager(options) {
|
|
11
|
-
const { storage, holderId, getNow, ttlMs, renewIntervalMs, waitTimeoutMs } = options, acquirePollIntervalMs = options.acquirePollIntervalMs ?? DEFAULT_ACQUIRE_POLL_INTERVAL_MS
|
|
11
|
+
const { storage, holderId, getNow, ttlMs, renewIntervalMs, waitTimeoutMs } = options, acquirePollIntervalMs = options.acquirePollIntervalMs ?? DEFAULT_ACQUIRE_POLL_INTERVAL_MS;
|
|
12
12
|
let stopped = !1, heldEpoch = null, heldEpochBytes = null, lastHolderBytes = null, renewalInterval = null, leaseLost = !1, inFlightRenewal = null;
|
|
13
13
|
const delay = options.delay ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
14
14
|
function reportLeaseLost(reason) {
|
|
@@ -81,7 +81,7 @@ export function createLeaseManager(options) {
|
|
|
81
81
|
committed = await storageConditionalBatch(storage, [{ key: KEYS.leaseHolder(), expectedValue: lastHolderBytes }], [{ type: "put", key: KEYS.leaseHolder(), value: holderBytes }]);
|
|
82
82
|
} catch {
|
|
83
83
|
const priorExpiry = decodeHolder(lastHolderBytes)?.expiresAt ?? 0;
|
|
84
|
-
if (getNow() >= priorExpiry
|
|
84
|
+
if (getNow() >= priorExpiry)
|
|
85
85
|
reportLeaseLost("renewal-unconfirmable");
|
|
86
86
|
return;
|
|
87
87
|
}
|
|
@@ -22,6 +22,7 @@ export function createForkedWorkflowState(_internals, workflowId, sourceState, v
|
|
|
22
22
|
type: sourceState.type,
|
|
23
23
|
status: "running",
|
|
24
24
|
input: sourceState.input,
|
|
25
|
+
workflowExecutionToken: crypto.randomUUID(),
|
|
25
26
|
versionTuple,
|
|
26
27
|
executionStateOwnerId: workflowId,
|
|
27
28
|
createdAt: forkedAt,
|
|
@@ -51,6 +51,9 @@ async function relaunchInlineWorkflowAfterResume(internals, latestState, args) {
|
|
|
51
51
|
await rehydrateChildCancellationHandlers(internals, workflowId, callbacks);
|
|
52
52
|
const context = new Context({
|
|
53
53
|
workflowId,
|
|
54
|
+
...latestState.workflowExecutionToken !== void 0 && {
|
|
55
|
+
workflowExecutionToken: latestState.workflowExecutionToken
|
|
56
|
+
},
|
|
54
57
|
workflowType: latestState.type,
|
|
55
58
|
startedAt: getWorkflowExecutionStartedAt(latestState),
|
|
56
59
|
abortController: workflowAbort,
|
|
@@ -85,6 +88,9 @@ async function relaunchWorkerWorkflowAfterResume(internals, latestState, args) {
|
|
|
85
88
|
const serialized = serializeCheckpoint(resumeCheckpoint);
|
|
86
89
|
internals.strategy.startWorkflow({
|
|
87
90
|
workflowId,
|
|
91
|
+
...latestState.workflowExecutionToken !== void 0 && {
|
|
92
|
+
workflowExecutionToken: latestState.workflowExecutionToken
|
|
93
|
+
},
|
|
88
94
|
workflowType: latestState.type,
|
|
89
95
|
input: latestState.input,
|
|
90
96
|
checkpoint: serialized,
|
|
@@ -2,8 +2,8 @@ import type { Checkpoint, StartOptions, WorkflowState } from '../../types.ts';
|
|
|
2
2
|
import type { EngineInternals } from '../internals.ts';
|
|
3
3
|
import { type LifecycleCallbacks, type RegistrationEntry } from './shared.ts';
|
|
4
4
|
export declare function runWorkflowStartInterceptor(_internals: EngineInternals, workflowId: string, workflowType: string, input: unknown, parentHeaders: Map<string, string> | undefined, callbacks: LifecycleCallbacks): Map<string, string> | undefined;
|
|
5
|
-
export declare function startWorkflowExecution(internals: EngineInternals, workflowId: string, workflowType: string, input: unknown, checkpoint: Checkpoint, nestingDepth: number, executionDeadline: number | undefined, executionStateOwnerId: string, _callbacks?: LifecycleCallbacks): void;
|
|
6
|
-
export declare function beginWorkflowExecution(internals: EngineInternals, workflowId: string, workflowType: string, input: unknown, checkpoint: Checkpoint, executionDeadline: number | undefined, executionStateOwnerId: string, _registration: RegistrationEntry, callbacks: LifecycleCallbacks, onStarted?: () => void): void;
|
|
5
|
+
export declare function startWorkflowExecution(internals: EngineInternals, workflowId: string, workflowExecutionToken: string | undefined, workflowType: string, input: unknown, checkpoint: Checkpoint, nestingDepth: number, executionDeadline: number | undefined, executionStateOwnerId: string, _callbacks?: LifecycleCallbacks): void;
|
|
6
|
+
export declare function beginWorkflowExecution(internals: EngineInternals, workflowId: string, workflowExecutionToken: string | undefined, workflowType: string, input: unknown, checkpoint: Checkpoint, executionDeadline: number | undefined, executionStateOwnerId: string, _registration: RegistrationEntry, callbacks: LifecycleCallbacks, onStarted?: () => void): void;
|
|
7
7
|
/**
|
|
8
8
|
* `defer: false` is an inline-only liveness gate: it awaits the moment the
|
|
9
9
|
* generator is first driven. A worker-mode start queues to the Worker transport
|
|
@@ -20,12 +20,13 @@ export function runWorkflowStartInterceptor(_internals, workflowId, workflowType
|
|
|
20
20
|
});
|
|
21
21
|
return capturedHeaders;
|
|
22
22
|
}
|
|
23
|
-
export function startWorkflowExecution(internals, workflowId, workflowType, input, checkpoint, nestingDepth, executionDeadline, executionStateOwnerId, _callbacks) {
|
|
23
|
+
export function startWorkflowExecution(internals, workflowId, workflowExecutionToken, workflowType, input, checkpoint, nestingDepth, executionDeadline, executionStateOwnerId, _callbacks) {
|
|
24
24
|
if (nestingDepth !== 0)
|
|
25
25
|
internals.workflowNestingDepths.set(workflowId, nestingDepth);
|
|
26
26
|
internals.workflowTypeByWorkflowId.set(workflowId, workflowType);
|
|
27
27
|
internals.strategy.startWorkflow({
|
|
28
28
|
workflowId,
|
|
29
|
+
...workflowExecutionToken !== void 0 && { workflowExecutionToken },
|
|
29
30
|
workflowType,
|
|
30
31
|
input,
|
|
31
32
|
checkpoint: serializeCheckpoint(checkpoint),
|
|
@@ -39,12 +40,13 @@ export function startWorkflowExecution(internals, workflowId, workflowType, inpu
|
|
|
39
40
|
}
|
|
40
41
|
});
|
|
41
42
|
}
|
|
42
|
-
export function beginWorkflowExecution(internals, workflowId, workflowType, input, checkpoint, executionDeadline, executionStateOwnerId, _registration, callbacks, onStarted) {
|
|
43
|
+
export function beginWorkflowExecution(internals, workflowId, workflowExecutionToken, workflowType, input, checkpoint, executionDeadline, executionStateOwnerId, _registration, callbacks, onStarted) {
|
|
43
44
|
const nestingDepth = internals.pendingNestingDepth ?? 0;
|
|
44
45
|
internals.pendingNestingDepth = void 0;
|
|
45
46
|
if (internals.inlineStrategy !== null) {
|
|
46
47
|
callbacks.queueInlineWorkflowExecutionStart({
|
|
47
48
|
workflowId,
|
|
49
|
+
...workflowExecutionToken !== void 0 && { workflowExecutionToken },
|
|
48
50
|
workflowType,
|
|
49
51
|
input,
|
|
50
52
|
checkpoint,
|
|
@@ -56,7 +58,7 @@ export function beginWorkflowExecution(internals, workflowId, workflowType, inpu
|
|
|
56
58
|
return;
|
|
57
59
|
}
|
|
58
60
|
callbacks.dispatchEvent(new WorkflowStartedEvent(workflowId, workflowType, input));
|
|
59
|
-
startWorkflowExecution(internals, workflowId, workflowType, input, checkpoint, nestingDepth, executionDeadline, executionStateOwnerId, callbacks);
|
|
61
|
+
startWorkflowExecution(internals, workflowId, workflowExecutionToken, workflowType, input, checkpoint, nestingDepth, executionDeadline, executionStateOwnerId, callbacks);
|
|
60
62
|
onStarted?.();
|
|
61
63
|
}
|
|
62
64
|
export function assertDeferSupported(internals, options, isDelayedStart) {
|
|
@@ -71,7 +73,7 @@ export async function beginExecutionAwaitingLiveness(internals, params, workflow
|
|
|
71
73
|
if (params.isDelayed)
|
|
72
74
|
return;
|
|
73
75
|
const liveness = params.options?.defer === !1 ? Promise.withResolvers() : void 0;
|
|
74
|
-
beginWorkflowExecution(internals, workflowId, params.type, params.input, params.checkpoint, params.state.executionDeadline, params.state.executionStateOwnerId ?? workflowId, params.registration, callbacks, liveness ? () => liveness.resolve() : void 0);
|
|
76
|
+
beginWorkflowExecution(internals, workflowId, params.state.workflowExecutionToken, params.type, params.input, params.checkpoint, params.state.executionDeadline, params.state.executionStateOwnerId ?? workflowId, params.registration, callbacks, liveness ? () => liveness.resolve() : void 0);
|
|
75
77
|
if (liveness)
|
|
76
78
|
await liveness.promise;
|
|
77
79
|
}
|
|
@@ -145,6 +145,7 @@ function buildInitialIdentitySlice(workflowId, type, input, versionTuple, execut
|
|
|
145
145
|
status: delayedStartTimer ? "pending" : "running",
|
|
146
146
|
input,
|
|
147
147
|
versionTuple,
|
|
148
|
+
workflowExecutionToken: crypto.randomUUID(),
|
|
148
149
|
...executionStateOwnerId !== void 0 && { executionStateOwnerId },
|
|
149
150
|
createdAt: now,
|
|
150
151
|
...!delayedStartTimer && { startedAt: now },
|
|
@@ -144,6 +144,9 @@ function launchInlineWorkflowFromCheckpoint(internals, workflowId, state, checkp
|
|
|
144
144
|
resetCancelHandlers(internals, workflowId);
|
|
145
145
|
const context = new Context({
|
|
146
146
|
workflowId,
|
|
147
|
+
...state.workflowExecutionToken !== void 0 && {
|
|
148
|
+
workflowExecutionToken: state.workflowExecutionToken
|
|
149
|
+
},
|
|
147
150
|
workflowType: state.type,
|
|
148
151
|
startedAt: getWorkflowExecutionStartedAt(state),
|
|
149
152
|
abortController: workflowAbort,
|
|
@@ -172,6 +175,9 @@ function launchWorkerWorkflowFromCheckpoint(internals, workflowId, state, checkp
|
|
|
172
175
|
const serialized = serializeCheckpoint(checkpoint);
|
|
173
176
|
internals.strategy.startWorkflow({
|
|
174
177
|
workflowId,
|
|
178
|
+
...state.workflowExecutionToken !== void 0 && {
|
|
179
|
+
workflowExecutionToken: state.workflowExecutionToken
|
|
180
|
+
},
|
|
175
181
|
workflowType: state.type,
|
|
176
182
|
input: state.input,
|
|
177
183
|
checkpoint: serialized,
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ContextOperationRequest } from '../context.ts';
|
|
2
|
+
import type { EngineInternals } from './internals.ts';
|
|
3
|
+
import { type ActivityOperationCallbacks } from './operations-activity.ts';
|
|
4
|
+
type MemoOperation = Extract<ContextOperationRequest, {
|
|
5
|
+
type: 'memo';
|
|
6
|
+
}>;
|
|
7
|
+
export declare function callMemoFunctionWithDurableActivityScope(internals: EngineInternals, workflowId: string, operation: MemoOperation, callbacks: {
|
|
8
|
+
getActivityOperationCallbacks?: () => ActivityOperationCallbacks;
|
|
9
|
+
persistCheckpoint: (workflowId: string, operation: ContextOperationRequest) => Promise<void>;
|
|
10
|
+
}): Promise<unknown>;
|
|
11
|
+
export {};
|