@lostgradient/weft 0.8.0 → 0.10.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 -5
- package/dist/alerting/alert-manager.d.ts +3 -1
- package/dist/alerting/alert-manager.js +5 -2
- package/dist/cli/generated/operation-client.generated.d.ts +1 -0
- package/dist/cli-main.js +78 -78
- package/dist/core/context/durable-operations.js +1 -1
- package/dist/core/context/index.d.ts +3 -1
- package/dist/core/context/index.js +10 -0
- package/dist/core/context/operation-request.d.ts +4 -0
- package/dist/core/context/parallel-cache-entry.d.ts +1 -1
- package/dist/core/context/parallel-cache-entry.js +12 -8
- package/dist/core/context/parallel-operations.d.ts +1 -1
- package/dist/core/context/parallel-operations.js +50 -8
- package/dist/core/context/run-operation.js +3 -2
- 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 +1 -1
- package/dist/core/engine/activity-heartbeat-tracking.js +5 -1
- package/dist/core/engine/anonymous-signal-sequence.js +0 -2
- package/dist/core/engine/async-activity-completion.d.ts +24 -54
- package/dist/core/engine/async-activity-completion.js +25 -90
- package/dist/core/engine/async-activity-records.d.ts +106 -0
- package/dist/core/engine/async-activity-records.js +124 -0
- package/dist/core/engine/bulk-operations-purge.js +2 -1
- package/dist/core/engine/bulk-operations.js +10 -29
- package/dist/core/engine/callback-creators-bundles.js +1 -1
- package/dist/core/engine/callback-creators-core.js +1 -0
- package/dist/core/engine/construction.d.ts +1 -3
- package/dist/core/engine/construction.js +2 -5
- package/dist/core/engine/deferred-consume-envelope.d.ts +10 -1
- package/dist/core/engine/deferred-consume-envelope.js +9 -1
- package/dist/core/engine/disposal.js +1 -0
- package/dist/core/engine/engine-internal-types.d.ts +2 -0
- package/dist/core/engine/engine-runtime-helpers.d.ts +8 -0
- package/dist/core/engine/engine-runtime-helpers.js +9 -0
- package/dist/core/engine/errors.js +1 -1
- package/dist/core/engine/index.d.ts +12 -2
- package/dist/core/engine/index.js +35 -16
- package/dist/core/engine/inline-launch-queue.js +1 -1
- package/dist/core/engine/internals.d.ts +25 -3
- package/dist/core/engine/lifecycle/fork-helpers.js +1 -0
- package/dist/core/engine/lifecycle/recovered-services.d.ts +4 -2
- package/dist/core/engine/lifecycle/recovered-services.js +37 -7
- package/dist/core/engine/lifecycle/resume.d.ts +2 -2
- package/dist/core/engine/lifecycle/resume.js +45 -7
- package/dist/core/engine/lifecycle/shared.d.ts +34 -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.d.ts +1 -1
- package/dist/core/engine/lifecycle/transition.js +9 -3
- package/dist/core/engine/lifecycle.d.ts +1 -1
- package/dist/core/engine/memo-durable-activity.js +8 -10
- package/dist/core/engine/operations-activity.d.ts +1 -1
- package/dist/core/engine/operations-activity.js +8 -6
- package/dist/core/engine/operations-coordination.d.ts +15 -1
- package/dist/core/engine/operations-coordination.js +43 -10
- package/dist/core/engine/operations-time.d.ts +2 -2
- package/dist/core/engine/operations-time.js +40 -6
- package/dist/core/engine/ownership-options.d.ts +1 -0
- package/dist/core/engine/ownership-options.js +14 -0
- package/dist/core/engine/retention.js +4 -0
- package/dist/core/engine/schedule-run-metadata.d.ts +3 -0
- package/dist/core/engine/schedule-run-metadata.js +29 -0
- package/dist/core/engine/schedule-run.js +19 -4
- package/dist/core/engine/schedules.js +7 -3
- package/dist/core/engine/sub-operation.js +6 -13
- package/dist/core/engine/termination/cleanup.js +18 -14
- 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/types/activity.d.ts +11 -0
- package/dist/core/types/checkpoint.d.ts +1 -0
- package/dist/core/types/options.d.ts +12 -0
- package/dist/core/types/schedules.d.ts +10 -0
- package/dist/core/types/services-resolution.d.ts +8 -3
- package/dist/core/types/state.d.ts +6 -0
- package/dist/core/types/workflow-builder.d.ts +2 -2
- package/dist/core/types/workflow-context.d.ts +40 -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 -2
- 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/authorization.d.ts +3 -3
- package/dist/server/fault-to-json-rpc.d.ts +2 -1
- package/dist/server/handler.js +28 -28
- package/dist/server/index.d.ts +2 -0
- package/dist/server/index.js +30 -30
- package/dist/server/json-rpc-dispatch.d.ts +2 -2
- package/dist/server/json-rpc-parse.d.ts +1 -1
- package/dist/server/json-rpc-protocol.d.ts +2 -2
- package/dist/server/json-rpc-websocket.d.ts +1 -1
- package/dist/server/operation-fault.d.ts +3 -1
- package/dist/server/operations/async-activity.js +2 -2
- package/dist/server/operations/create-schedule.d.ts +2 -0
- package/dist/server/operations/create-schedule.js +13 -2
- package/dist/server/principal.d.ts +2 -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/stdio-session.d.ts +4 -4
- 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/storage/auto.d.ts +36 -18
- package/dist/storage/auto.js +1 -1
- package/dist/storage/compressed-storage.js +1 -1
- package/dist/storage/http.js +2 -2
- package/dist/storage/index.d.ts +1 -0
- package/dist/storage/indexeddb.d.ts +6 -1
- package/dist/storage/indexeddb.js +1 -1
- package/dist/storage/interface.d.ts +1 -0
- 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.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 +33 -33
- 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 +2 -2
|
@@ -11,7 +11,7 @@ export function prepareSleepOperation(internals, duration) {
|
|
|
11
11
|
console.log(` \u2192 Creating checkpoint at step ${step}`);
|
|
12
12
|
console.log(` \u2192 Scheduling timer for ${milliseconds}ms`);
|
|
13
13
|
}
|
|
14
|
-
const operationId =
|
|
14
|
+
const operationId = `${internals.context.workflowId}:${step}`, callerStack = captureCallerStack(), referenceTime = internals.sleepReferenceTime ?? internals.getNow();
|
|
15
15
|
internals.sleepReferenceTime = void 0;
|
|
16
16
|
return {
|
|
17
17
|
cached: !1,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ComposedWorkflowInterceptor } from '../interceptor.ts';
|
|
2
2
|
import type { HumanReviewOptions, HumanReviewResult } from '../review/index.ts';
|
|
3
|
-
import type { ActivityCallable, ActivityCallOptions, AwaitChildWorkflowOptions, ChildWorkflowHandle, ChildWorkflowTarget, DetachedChildWorkflowOptions, Duration, QueryDefinition, RunAllResult, SearchAttributeHandle, SearchAttributeValue, SignalDefinition, UpdateDefinition, WorkflowContext, WorkflowLogger, WorkflowMapOptions, WorkflowOperation, WorkflowOperationTupleResult, WorkflowPipeStageDefinition, WorkflowReduceInput, WorkflowReduceOptions, WorkflowRunAllBranch, WorkflowStateNamespace } from '../types.ts';
|
|
3
|
+
import type { ActivityCallable, ActivityCallOptions, AwaitChildWorkflowOptions, ChildWorkflowHandle, ChildWorkflowTarget, DetachedChildWorkflowOptions, Duration, QueryDefinition, RunAllResult, SearchAttributeHandle, SearchAttributeValue, SignalDefinition, UpdateDefinition, WorkflowContext, WorkflowKeyedRaceResult, WorkflowLogger, WorkflowMapOptions, WorkflowOperation, WorkflowOperationTupleResult, WorkflowPipeStageDefinition, WorkflowReduceInput, WorkflowReduceOptions, WorkflowRunAllBranch, WorkflowStateNamespace } from '../types.ts';
|
|
4
4
|
import type { ContextOperationRequest } from './operation-request.ts';
|
|
5
5
|
import type { ContextOptions, ErasedSagaStep, OffloadReference, StreamReference, StreamSink } from './types.ts';
|
|
6
6
|
import * as contextUpdates from './updates.ts';
|
|
@@ -23,6 +23,7 @@ export declare function setContextWorkflowInterceptor(context: Context, workflow
|
|
|
23
23
|
export declare class Context implements WorkflowContext {
|
|
24
24
|
#private;
|
|
25
25
|
readonly workflowId: string;
|
|
26
|
+
readonly workflowExecutionToken: string | undefined;
|
|
26
27
|
readonly workflowType: string;
|
|
27
28
|
readonly startedAt: number;
|
|
28
29
|
readonly signal: AbortSignal;
|
|
@@ -81,6 +82,7 @@ export declare class Context implements WorkflowContext {
|
|
|
81
82
|
review(options: HumanReviewOptions): Generator<ContextOperationRequest, HumanReviewResult, unknown>;
|
|
82
83
|
all<const TOperations extends readonly WorkflowOperation<unknown>[]>(operations: TOperations): Generator<ContextOperationRequest, WorkflowOperationTupleResult<TOperations>, unknown>;
|
|
83
84
|
race<const TOperations extends readonly WorkflowOperation<unknown>[]>(operations: TOperations): Generator<ContextOperationRequest, WorkflowOperationTupleResult<TOperations>[number], unknown>;
|
|
85
|
+
raceKeyed<const TOperations extends Readonly<Record<string, WorkflowOperation<unknown>>>>(operations: TOperations): Generator<ContextOperationRequest, WorkflowKeyedRaceResult<TOperations>, unknown>;
|
|
84
86
|
memo<T>(key: string, fn: () => T | Promise<T>): Generator<ContextOperationRequest, T, unknown>;
|
|
85
87
|
offload<T>(key: string, fn: () => Promise<T>): Generator<ContextOperationRequest, OffloadReference, unknown>;
|
|
86
88
|
stream(key: string, fn: (sink: StreamSink) => AsyncGenerator<unknown, void, unknown>): Generator<ContextOperationRequest, StreamReference, unknown>;
|
|
@@ -21,12 +21,14 @@ export function setContextWorkflowInterceptor(context, workflowInterceptor) {
|
|
|
21
21
|
|
|
22
22
|
export class Context {
|
|
23
23
|
workflowId;
|
|
24
|
+
workflowExecutionToken;
|
|
24
25
|
workflowType;
|
|
25
26
|
startedAt;
|
|
26
27
|
signal;
|
|
27
28
|
#log;
|
|
28
29
|
constructor(options) {
|
|
29
30
|
this.workflowId = options.workflowId;
|
|
31
|
+
this.workflowExecutionToken = options.workflowExecutionToken;
|
|
30
32
|
this.workflowType = options.workflowType;
|
|
31
33
|
this.startedAt = options.startedAt;
|
|
32
34
|
this.signal = options.abortController.signal;
|
|
@@ -154,6 +156,14 @@ export class Context {
|
|
|
154
156
|
*race(operations) {
|
|
155
157
|
return yield* parallelOperations.race(this, getInternals(this), [...operations]);
|
|
156
158
|
}
|
|
159
|
+
*raceKeyed(operations) {
|
|
160
|
+
if (Object.getOwnPropertySymbols(operations).length > 0)
|
|
161
|
+
throw TypeError("ctx.raceKeyed branch names must be strings or numbers, not symbols");
|
|
162
|
+
const entries = Object.entries(operations);
|
|
163
|
+
if (entries.length === 0)
|
|
164
|
+
throw TypeError("ctx.raceKeyed requires at least one branch");
|
|
165
|
+
return yield* parallelOperations.race(this, getInternals(this), entries.map(([, operation]) => operation), entries.map(([key]) => key));
|
|
166
|
+
}
|
|
157
167
|
*memo(key, fn) {
|
|
158
168
|
return yield* parallelOperations.memo(this, getInternals(this), key, fn);
|
|
159
169
|
}
|
|
@@ -30,6 +30,8 @@ export type ContextOperationRequest = {
|
|
|
30
30
|
activityName: string;
|
|
31
31
|
fn?: (input: unknown, context?: unknown) => unknown;
|
|
32
32
|
input: unknown;
|
|
33
|
+
/** Immutable owner token for this workflow run, used to fence external side effects. */
|
|
34
|
+
workflowExecutionToken?: string;
|
|
33
35
|
callerStack?: string;
|
|
34
36
|
options?: Record<string, unknown>;
|
|
35
37
|
/** Dispatch attempt used for worker payloads, interceptors, and reconciliation verifiers. */
|
|
@@ -125,6 +127,8 @@ export type ContextOperationRequest = {
|
|
|
125
127
|
type: 'race';
|
|
126
128
|
operationId: string;
|
|
127
129
|
operations: ContextOperationRequest[];
|
|
130
|
+
/** Ordered branch names for `ctx.raceKeyed`; absent for positional `ctx.race`. */
|
|
131
|
+
branchNames?: string[];
|
|
128
132
|
callerStack?: string;
|
|
129
133
|
} | {
|
|
130
134
|
type: 'memo';
|
|
@@ -57,7 +57,7 @@ export type ParallelOperationCacheEntry = {
|
|
|
57
57
|
formatVersion: 2;
|
|
58
58
|
variant: 'all' | 'race' | 'run-all';
|
|
59
59
|
branches: ParallelBranchSlot[];
|
|
60
|
-
/** Ordered key list for `run-all`; absent for `all` and `race`. */
|
|
60
|
+
/** Ordered key list for `run-all` or `raceKeyed`; absent for `all` and positional `race`. */
|
|
61
61
|
branchNames?: string[];
|
|
62
62
|
subOperationCount: number;
|
|
63
63
|
};
|
|
@@ -41,20 +41,24 @@ function hasParallelOperationCacheMarker(value) {
|
|
|
41
41
|
return value !== null && typeof value === "object" && value.__weftParallelOperationCache === !0;
|
|
42
42
|
}
|
|
43
43
|
function hasValidBranchTopology(variant, branches, subOperationCount, branchNames) {
|
|
44
|
-
if (variant === "race")
|
|
45
|
-
|
|
46
|
-
return !1;
|
|
47
|
-
const winner = branches[0];
|
|
48
|
-
if (winner == null || typeof winner !== "object")
|
|
49
|
-
return !1;
|
|
50
|
-
return winner.status === "fulfilled" && branchNames === void 0;
|
|
51
|
-
}
|
|
44
|
+
if (variant === "race")
|
|
45
|
+
return hasValidRaceTopology(branches, subOperationCount, branchNames);
|
|
52
46
|
if (branches.length !== subOperationCount)
|
|
53
47
|
return !1;
|
|
54
48
|
if (variant === "run-all")
|
|
55
49
|
return Array.isArray(branchNames) && branchNames.length === subOperationCount;
|
|
56
50
|
return branchNames === void 0;
|
|
57
51
|
}
|
|
52
|
+
function hasValidRaceTopology(branches, subOperationCount, branchNames) {
|
|
53
|
+
if (branches.length !== 1 || subOperationCount < 1)
|
|
54
|
+
return !1;
|
|
55
|
+
const winner = branches[0];
|
|
56
|
+
if (winner == null || typeof winner !== "object")
|
|
57
|
+
return !1;
|
|
58
|
+
if (winner.status !== "fulfilled")
|
|
59
|
+
return !1;
|
|
60
|
+
return branchNames === void 0 || Array.isArray(branchNames) && branchNames.length === subOperationCount;
|
|
61
|
+
}
|
|
58
62
|
export function isParallelOperationCacheEntry(value) {
|
|
59
63
|
if (value === null || typeof value !== "object")
|
|
60
64
|
return !1;
|
|
@@ -4,6 +4,6 @@ import type { ContextOperationRequest } from './operation-request.ts';
|
|
|
4
4
|
import { assertValidParallelOperationCacheEntry, BranchTopologyChangedError, createParallelOperationCacheEntry, isParallelOperationCacheEntry, type ParallelBranchSlot, type ParallelOperationCacheEntry } from './parallel-cache-entry.ts';
|
|
5
5
|
export { assertValidParallelOperationCacheEntry, BranchTopologyChangedError, createParallelOperationCacheEntry, isParallelOperationCacheEntry, type ParallelBranchSlot, type ParallelOperationCacheEntry, };
|
|
6
6
|
export declare function all(context: Context, internals: ContextInternals, operations: Generator<ContextOperationRequest, unknown, unknown>[]): Generator<ContextOperationRequest, unknown[], unknown>;
|
|
7
|
-
export declare function race(context: Context, internals: ContextInternals, operations: Generator<ContextOperationRequest, unknown, unknown>[]): Generator<ContextOperationRequest, unknown, unknown>;
|
|
7
|
+
export declare function race(context: Context, internals: ContextInternals, operations: Generator<ContextOperationRequest, unknown, unknown>[], branchNames?: string[]): Generator<ContextOperationRequest, unknown, unknown>;
|
|
8
8
|
export declare function memo<T>(context: Context, internals: ContextInternals, key: string, fn: () => T | Promise<T>): Generator<ContextOperationRequest, T, unknown>;
|
|
9
9
|
export declare function runAll<T extends Record<string, readonly [Function] | readonly [Function, unknown]>>(context: Context, internals: ContextInternals, branches: T): Generator<ContextOperationRequest, Record<keyof T, unknown>, unknown>;
|
|
@@ -83,7 +83,7 @@ function buildFulfilledAllEntry(values, operationId, subOperationCount) {
|
|
|
83
83
|
operationId: `${operationId}:${i}`
|
|
84
84
|
})), subOperationCount);
|
|
85
85
|
}
|
|
86
|
-
export function* race(context, internals, operations) {
|
|
86
|
+
export function* race(context, internals, operations, branchNames) {
|
|
87
87
|
const step = internals.stepIndex++;
|
|
88
88
|
if (internals.accumulatedResults?.has(step)) {
|
|
89
89
|
const cached = internals.accumulatedResults.get(step);
|
|
@@ -91,32 +91,74 @@ export function* race(context, internals, operations) {
|
|
|
91
91
|
if (isParallelOperationCacheEntry(cached)) {
|
|
92
92
|
if (cached.variant !== "race")
|
|
93
93
|
throw new BranchTopologyChangedError(`ctx.race step ${step} found a cached entry of variant '${cached.variant}'. The same step must use the same parallel primitive across retries.`);
|
|
94
|
-
|
|
95
|
-
throw new BranchTopologyChangedError(`ctx.race branch count changed across retry: expected ${cached.subOperationCount}, got ${operations.length}. Branch count must be deterministic.`);
|
|
94
|
+
assertRaceBranchTopology(operations.length, branchNames, cached);
|
|
96
95
|
const winner = cached.branches[0];
|
|
97
|
-
if (winner?.status !== "fulfilled")
|
|
98
|
-
throw new BranchTopologyChangedError(`ctx.race step ${step} cached entry has no fulfilled winner slot \u2014 entry is malformed.`);
|
|
99
96
|
internals.stepIndex += cached.subOperationCount;
|
|
100
97
|
return winner.value;
|
|
101
98
|
}
|
|
99
|
+
if (branchNames !== void 0)
|
|
100
|
+
throw new BranchTopologyChangedError(`ctx.raceKeyed step ${step} found a raw cached race value without keyed branch topology. The same step must use raceKeyed across retries.`);
|
|
102
101
|
return cached;
|
|
103
102
|
}
|
|
104
|
-
const
|
|
103
|
+
const operationId = `race:${step}`;
|
|
104
|
+
let subOperations;
|
|
105
|
+
if (branchNames === void 0)
|
|
106
|
+
subOperations = primeParallelOperations(operations);
|
|
107
|
+
else {
|
|
108
|
+
const primed = primeKeyedRaceOperations(operations);
|
|
109
|
+
subOperations = primed.subOperations;
|
|
110
|
+
if (primed.synchronousWinner !== void 0) {
|
|
111
|
+
const result = { key: branchNames[primed.synchronousWinner.index], value: primed.synchronousWinner.value };
|
|
112
|
+
cacheRaceWinner(context, step, result, operationId, operations.length, branchNames);
|
|
113
|
+
return result;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
105
116
|
stampDeterministicOperationIds(subOperations, operationId);
|
|
106
117
|
const callerStack = captureCallerStack(), result = yield {
|
|
107
118
|
type: "race",
|
|
108
119
|
operationId,
|
|
109
120
|
operations: subOperations,
|
|
121
|
+
...branchNames !== void 0 ? { branchNames } : {},
|
|
110
122
|
callerStack
|
|
111
123
|
};
|
|
124
|
+
cacheRaceWinner(context, step, result, operationId, subOperations.length, branchNames);
|
|
125
|
+
return result;
|
|
126
|
+
}
|
|
127
|
+
function primeKeyedRaceOperations(operations) {
|
|
128
|
+
const subOperations = [];
|
|
129
|
+
let synchronousWinner;
|
|
130
|
+
for (const [index, operation] of operations.entries()) {
|
|
131
|
+
const primed = operation.next();
|
|
132
|
+
if (primed.done)
|
|
133
|
+
synchronousWinner ??= { index, value: primed.value };
|
|
134
|
+
else
|
|
135
|
+
subOperations.push(primed.value);
|
|
136
|
+
}
|
|
137
|
+
return { subOperations, synchronousWinner };
|
|
138
|
+
}
|
|
139
|
+
function cacheRaceWinner(context, step, result, operationId, subOperationCount, branchNames) {
|
|
112
140
|
context.accumulatedResults.set(step, {
|
|
113
141
|
__weftParallelOperationCache: !0,
|
|
114
142
|
formatVersion: 2,
|
|
115
143
|
variant: "race",
|
|
116
144
|
branches: [{ status: "fulfilled", value: result, operationId: `${operationId}:winner` }],
|
|
117
|
-
|
|
145
|
+
...branchNames !== void 0 ? { branchNames } : {},
|
|
146
|
+
subOperationCount
|
|
118
147
|
});
|
|
119
|
-
|
|
148
|
+
}
|
|
149
|
+
function sameBranchNames(left, right) {
|
|
150
|
+
if (left === void 0 || right === void 0)
|
|
151
|
+
return left === right;
|
|
152
|
+
return left.length === right.length && left.every((name, index) => name === right[index]);
|
|
153
|
+
}
|
|
154
|
+
function assertRaceBranchTopology(operationCount, branchNames, cached) {
|
|
155
|
+
if (operationCount !== cached.subOperationCount)
|
|
156
|
+
throw new BranchTopologyChangedError(`ctx.race branch count changed across retry: expected ${cached.subOperationCount}, got ${operationCount}. Branch count must be deterministic.`);
|
|
157
|
+
if (!sameBranchNames(branchNames, cached.branchNames))
|
|
158
|
+
throw new BranchTopologyChangedError(`ctx.race branch names changed across retry: expected ${formatBranchNames(cached.branchNames)}, got ${formatBranchNames(branchNames)}. Branch names and order must be deterministic.`);
|
|
159
|
+
}
|
|
160
|
+
function formatBranchNames(branchNames) {
|
|
161
|
+
return branchNames === void 0 ? "positional branches" : JSON.stringify(branchNames);
|
|
120
162
|
}
|
|
121
163
|
function stampDeterministicOperationIds(subOperations, parentOperationId) {
|
|
122
164
|
for (let i = 0;i < subOperations.length; i++) {
|
|
@@ -74,7 +74,7 @@ function getActivityName(activity, explicitName) {
|
|
|
74
74
|
function getActivityFunction(activity) {
|
|
75
75
|
return typeof activity === "function" ? activity : void 0;
|
|
76
76
|
}
|
|
77
|
-
function createFreshRunActivityRequest(internals, step, activityName, activityFunction, input, options, activityStateKey) {
|
|
77
|
+
function createFreshRunActivityRequest(internals, step, activityName, activityFunction, input, options, activityStateKey, workflowExecutionToken) {
|
|
78
78
|
const queue = options?.queue ?? "default";
|
|
79
79
|
if (internals.explainMode) {
|
|
80
80
|
console.log(`[weft] ctx.run(${activityName}, ${JSON.stringify(input)})`);
|
|
@@ -87,6 +87,7 @@ function createFreshRunActivityRequest(internals, step, activityName, activityFu
|
|
|
87
87
|
activityName,
|
|
88
88
|
step,
|
|
89
89
|
...activityStateKey === void 0 ? {} : { activityStateKey },
|
|
90
|
+
...workflowExecutionToken === void 0 ? {} : { workflowExecutionToken },
|
|
90
91
|
...activityFunction !== void 0 ? { fn: activityFunction } : {},
|
|
91
92
|
input,
|
|
92
93
|
callerStack: captureCallerStack(),
|
|
@@ -141,7 +142,7 @@ export function createRunActivityRequestAtStep(context, activity, rest, step, co
|
|
|
141
142
|
return cachedRequest;
|
|
142
143
|
const retryPolicy = resolveActivityRetryPolicy(activity, options), scheduleToCloseTimeout = resolveActivityScheduleToCloseTimeout(activity, options);
|
|
143
144
|
return {
|
|
144
|
-
request: createFreshRunActivityRequest(internals, step, activityName, activityFunction, input, resolveDispatchedActivityOptions(activity, options), configuration.activityStateKey),
|
|
145
|
+
request: createFreshRunActivityRequest(internals, step, activityName, activityFunction, input, resolveDispatchedActivityOptions(activity, options), configuration.activityStateKey, context.workflowExecutionToken),
|
|
145
146
|
step,
|
|
146
147
|
retryStateKey,
|
|
147
148
|
...cacheResultStep === void 0 ? {} : { cacheResultStep },
|
|
@@ -24,6 +24,7 @@ function assignOptionalContextOptions(options, internals) {
|
|
|
24
24
|
function createSpeculativeChildOptions(parent, internals) {
|
|
25
25
|
const options = {
|
|
26
26
|
workflowId: parent.workflowId,
|
|
27
|
+
...parent.workflowExecutionToken === void 0 ? {} : { workflowExecutionToken: parent.workflowExecutionToken },
|
|
27
28
|
workflowType: parent.workflowType,
|
|
28
29
|
startedAt: parent.startedAt,
|
|
29
30
|
abortController: internals.abortController,
|
|
@@ -52,4 +52,4 @@ export declare function warnIfRetryMissingHeartbeat(internals: EngineInternals,
|
|
|
52
52
|
* tracking above; `completeAsync` is supplied by the caller (it owns the
|
|
53
53
|
* async-completion token machinery).
|
|
54
54
|
*/
|
|
55
|
-
export declare function buildActivityContext(internals: EngineInternals, workflowId: string, step: ActivityHeartbeatKey, signal: AbortSignal, completeAsync: () => never): ActivityContext;
|
|
55
|
+
export declare function buildActivityContext(internals: EngineInternals, workflowId: string, workflowExecutionToken: string | undefined, step: ActivityHeartbeatKey, attempt: number, signal: AbortSignal, completeAsync: () => never): ActivityContext;
|
|
@@ -35,9 +35,13 @@ export function warnIfRetryMissingHeartbeat(internals, workflowId, step, attempt
|
|
|
35
35
|
return;
|
|
36
36
|
internals.engine.dispatchEvent(new DevelopmentWarningEvent(workflowId, `Activity retry (attempt ${attempt}) at ${activityHeartbeatKeyLabel(step)} has no lastHeartbeatDetails. Either the previous attempt never recorded heartbeat details (it never called heartbeat(), or called it with no details), or the engine process restarted and discarded the in-memory heartbeat (it is not durable). The resumable-batch pattern only resumes across in-process retries; design the activity to restart cleanly when lastHeartbeatDetails is undefined.`, [activityHeartbeatFieldPath(step)]));
|
|
37
37
|
}
|
|
38
|
-
export function buildActivityContext(internals, workflowId, step, signal, completeAsync) {
|
|
38
|
+
export function buildActivityContext(internals, workflowId, workflowExecutionToken, step, attempt, signal, completeAsync) {
|
|
39
39
|
return {
|
|
40
40
|
signal,
|
|
41
|
+
...workflowExecutionToken !== void 0 && {
|
|
42
|
+
workflowExecutionToken,
|
|
43
|
+
activityAttemptToken: `${workflowExecutionToken}:activity:${String(step)}:${String(attempt)}`
|
|
44
|
+
},
|
|
41
45
|
lastHeartbeatDetails: readLastHeartbeatForStep(internals, workflowId, step),
|
|
42
46
|
heartbeat: (details) => {
|
|
43
47
|
internals.heartbeatDetails.set(workflowId, details);
|
|
@@ -94,8 +94,6 @@ function extractAnonymousSignalSequence(key) {
|
|
|
94
94
|
return Number.isSafeInteger(sequence) && sequence >= 0 ? sequence : null;
|
|
95
95
|
}
|
|
96
96
|
function decodeSignalSequence(bytes) {
|
|
97
|
-
if (bytes === null)
|
|
98
|
-
return 0;
|
|
99
97
|
const value = decode(bytes);
|
|
100
98
|
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0)
|
|
101
99
|
throw Error("Stored anonymous signal sequence must be a non-negative safe integer");
|
|
@@ -26,9 +26,33 @@
|
|
|
26
26
|
* arrives after token recovery but before replay has adopted the workflow
|
|
27
27
|
* generator, the engine buffers the completion or failure outcome and drains it
|
|
28
28
|
* when replay reaches the same deterministic token.
|
|
29
|
+
*
|
|
30
|
+
* Acknowledgement durability: `completeAsyncActivity` / `failAsyncActivity`
|
|
31
|
+
* resolve only after ONE fenced batch has durably (a) deleted the single-use
|
|
32
|
+
* token record and (b) written a resolution record
|
|
33
|
+
* ({@link KEYS.asyncActivityResolution}) carrying the supplied outcome. A crash
|
|
34
|
+
* any time after the acknowledgement therefore cannot lose the outcome:
|
|
35
|
+
* recovery reloads the resolution record, queues it, and redelivers it when
|
|
36
|
+
* replay re-parks on the same deterministic token. The resolution record is
|
|
37
|
+
* deleted through the atomic side-effect buffer, so in the normal case it rides
|
|
38
|
+
* the very checkpoint that records the resumed result; a record whose delete
|
|
39
|
+
* never commits is simply redelivered (idempotent for a deterministic token) or
|
|
40
|
+
* swept by terminal cleanup/purge. If the acknowledgement batch itself fails,
|
|
41
|
+
* the in-memory token claim is restored and the error propagates — the caller
|
|
42
|
+
* learns the completion did NOT stick and can retry the still-live token.
|
|
43
|
+
*
|
|
44
|
+
* One caveat survives a crash: the failure path's raw thrown reason
|
|
45
|
+
* (`originalReason`) is delivered as-is only within the acknowledging process.
|
|
46
|
+
* A redelivery after recovery reconstructs the error from the persisted outcome
|
|
47
|
+
* (message, name, failure category) — the same fidelity the worker resume path
|
|
48
|
+
* has always had.
|
|
49
|
+
*
|
|
50
|
+
* The persisted record shapes, decode guards, key derivations, and the queued
|
|
51
|
+
* resolution buffer live in `async-activity-records.ts`.
|
|
29
52
|
*/
|
|
30
53
|
import type { OperationOutcome } from '../types.ts';
|
|
31
54
|
import { WeftError } from '../weft-error.ts';
|
|
55
|
+
import { type PendingAsyncActivity } from './async-activity-records.ts';
|
|
32
56
|
import type { EngineInternals } from './internals.ts';
|
|
33
57
|
type AsyncActivityResolutionCallbacks = {
|
|
34
58
|
feedOperationResult: (workflowId: string, outcome: OperationOutcome, originalReason?: {
|
|
@@ -36,12 +60,6 @@ type AsyncActivityResolutionCallbacks = {
|
|
|
36
60
|
}) => void;
|
|
37
61
|
finalizeTimeline: (workflowId: string, status: 'completed' | 'failed', output: unknown) => void;
|
|
38
62
|
};
|
|
39
|
-
/**
|
|
40
|
-
* Per-workflow prefix for all async-activity storage keys. Used by cleanup and
|
|
41
|
-
* purge paths that need to sweep every async-activity record for a workflow
|
|
42
|
-
* without enumerating individual tokens.
|
|
43
|
-
*/
|
|
44
|
-
export declare function asyncActivityWorkflowPrefix(workflowId: string): string;
|
|
45
63
|
/**
|
|
46
64
|
* Sentinel thrown by `ActivityContext.completeAsync()` to signal that the
|
|
47
65
|
* activity is handing off to an out-of-band completion. The engine recognizes
|
|
@@ -73,48 +91,6 @@ export declare class AsyncActivityTokenNotFoundError extends WeftError<'AsyncAct
|
|
|
73
91
|
readonly token: string;
|
|
74
92
|
constructor(token: string);
|
|
75
93
|
}
|
|
76
|
-
/**
|
|
77
|
-
* In-memory record of an activity that deferred to out-of-band completion and
|
|
78
|
-
* is awaiting `completeAsyncActivity` / `failAsyncActivity`.
|
|
79
|
-
*/
|
|
80
|
-
export type PendingAsyncActivity = {
|
|
81
|
-
readonly token: string;
|
|
82
|
-
readonly workflowId: string;
|
|
83
|
-
readonly activityName: string;
|
|
84
|
-
readonly operationId: string;
|
|
85
|
-
readonly step: number;
|
|
86
|
-
readonly attempt: number;
|
|
87
|
-
readonly createdAt: number;
|
|
88
|
-
};
|
|
89
|
-
export type PendingAsyncActivityResolution = {
|
|
90
|
-
readonly token: string;
|
|
91
|
-
readonly outcome: OperationOutcome;
|
|
92
|
-
readonly originalReason?: {
|
|
93
|
-
value: unknown;
|
|
94
|
-
};
|
|
95
|
-
readonly timelineStatus: 'completed' | 'failed';
|
|
96
|
-
readonly timelineOutput: unknown;
|
|
97
|
-
};
|
|
98
|
-
/**
|
|
99
|
-
* Derive the durable, deterministic task token for an async activity.
|
|
100
|
-
*
|
|
101
|
-
* The token is anchored to the workflow id, the activity state key, and the
|
|
102
|
-
* dispatch attempt — all of which are stable across replay — so a workflow that
|
|
103
|
-
* crashes while parked on an async activity mints the identical token after
|
|
104
|
-
* recovery. Plain `ctx.run()` uses the workflow step as the state key.
|
|
105
|
-
* `operationId` is deliberately excluded because it is regenerated on every
|
|
106
|
-
* yield and would change on replay.
|
|
107
|
-
*/
|
|
108
|
-
export declare function deriveAsyncActivityToken(workflowId: string, step: number | string, attempt: number): string;
|
|
109
|
-
/**
|
|
110
|
-
* Register a deferred activity: record it in memory and durably, then announce
|
|
111
|
-
* the token via {@link ActivityAsyncPendingEvent}. Idempotent on `token`: if the
|
|
112
|
-
* token is already registered (e.g. because `recoverPendingAsyncActivities` loaded
|
|
113
|
-
* it before the workflow replayed and re-deferred), the durable record is
|
|
114
|
-
* refreshed but the event is NOT re-emitted, preventing duplicate side-effects
|
|
115
|
-
* (e.g. re-sending a webhook notification) on replay.
|
|
116
|
-
*/
|
|
117
|
-
export declare function registerPendingAsyncActivity(internals: EngineInternals, pending: PendingAsyncActivity): Promise<void>;
|
|
118
94
|
/**
|
|
119
95
|
* Park an activity that threw {@link AsyncActivityDeferral}: register the
|
|
120
96
|
* pending entry durably and return a promise that never settles, so the
|
|
@@ -123,12 +99,6 @@ export declare function registerPendingAsyncActivity(internals: EngineInternals,
|
|
|
123
99
|
* one-liner.
|
|
124
100
|
*/
|
|
125
101
|
export declare function parkDeferredAsyncActivity(internals: EngineInternals, deferral: AsyncActivityDeferral, details: Omit<PendingAsyncActivity, 'token' | 'createdAt'>, callbacks: AsyncActivityResolutionCallbacks): Promise<never>;
|
|
126
|
-
/**
|
|
127
|
-
* Reload pending async-activity records from storage into memory. Called by
|
|
128
|
-
* `recoverAll()` so a token minted before a crash is resolvable again — even
|
|
129
|
-
* before the recovered workflow has replayed far enough to re-register it.
|
|
130
|
-
*/
|
|
131
|
-
export declare function recoverPendingAsyncActivities(internals: EngineInternals): Promise<void>;
|
|
132
102
|
/**
|
|
133
103
|
* Complete a deferred activity out-of-band with `result`, resuming the parked
|
|
134
104
|
* workflow as though the activity had returned `result` inline.
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import { KEYS
|
|
2
|
-
import { decode, encode } from "../codec.js";
|
|
3
|
-
import { ActivityAsyncPendingEvent } from "../events.js";
|
|
1
|
+
import { KEYS } from "../../storage/interface.js";
|
|
4
2
|
import { assertPayloadWithinLimit } from "../payload-size.js";
|
|
5
3
|
import { WeftError } from "../weft-error.js";
|
|
4
|
+
import {
|
|
5
|
+
buildAsyncActivityAcknowledgementOperations,
|
|
6
|
+
queuePendingAsyncActivityResolution,
|
|
7
|
+
registerPendingAsyncActivity,
|
|
8
|
+
shouldBufferPendingAsyncActivityResolution,
|
|
9
|
+
takePendingAsyncActivityResolution
|
|
10
|
+
} from "./async-activity-records.js";
|
|
6
11
|
import { stageAtomicWorkflowCommitSideEffects } from "./checkpoint-side-effects.js";
|
|
7
12
|
import { commitFencedEngineWrite } from "./fenced-write.js";
|
|
8
|
-
const ASYNC_ACTIVITY_TOKEN_PREFIX = "async-act:v1", ASYNC_ACTIVITY_KEY_PREFIX = "async-act:v1:";
|
|
9
|
-
export function asyncActivityWorkflowPrefix(workflowId) {
|
|
10
|
-
return `${ASYNC_ACTIVITY_KEY_PREFIX}${encodeStorageKeyComponent(workflowId)}:`;
|
|
11
|
-
}
|
|
12
13
|
|
|
13
14
|
export class AsyncActivityDeferral extends Error {
|
|
14
15
|
token;
|
|
@@ -26,43 +27,10 @@ export class AsyncActivityTokenNotFoundError extends WeftError {
|
|
|
26
27
|
this.token = token;
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
|
-
function isPersistedAsyncActivity(value) {
|
|
30
|
-
if (typeof value !== "object" || value === null)
|
|
31
|
-
return !1;
|
|
32
|
-
const record = value;
|
|
33
|
-
return record.version === 1 && typeof record.token === "string" && typeof record.workflowId === "string" && typeof record.activityName === "string" && typeof record.operationId === "string" && typeof record.step === "number" && typeof record.attempt === "number" && typeof record.createdAt === "number";
|
|
34
|
-
}
|
|
35
|
-
export function deriveAsyncActivityToken(workflowId, step, attempt) {
|
|
36
|
-
return `${ASYNC_ACTIVITY_TOKEN_PREFIX}:${workflowId}:${step}:${attempt}`;
|
|
37
|
-
}
|
|
38
|
-
function buildPersistPendingAsyncActivityOperation(pending) {
|
|
39
|
-
const record = {
|
|
40
|
-
version: 1,
|
|
41
|
-
token: pending.token,
|
|
42
|
-
workflowId: pending.workflowId,
|
|
43
|
-
activityName: pending.activityName,
|
|
44
|
-
operationId: pending.operationId,
|
|
45
|
-
step: pending.step,
|
|
46
|
-
attempt: pending.attempt,
|
|
47
|
-
createdAt: pending.createdAt
|
|
48
|
-
};
|
|
49
|
-
return {
|
|
50
|
-
type: "put",
|
|
51
|
-
key: KEYS.asyncActivity(pending.workflowId, pending.token),
|
|
52
|
-
value: encode(record)
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
export async function registerPendingAsyncActivity(internals, pending) {
|
|
56
|
-
const alreadyRegistered = internals.pendingAsyncActivities.has(pending.token);
|
|
57
|
-
internals.pendingAsyncActivities.set(pending.token, pending);
|
|
58
|
-
await commitFencedEngineWrite(internals, [buildPersistPendingAsyncActivityOperation(pending)], [], () => Error(`Async activity registration for token "${pending.token}" lost its precondition.`));
|
|
59
|
-
if (!alreadyRegistered)
|
|
60
|
-
internals.engine.dispatchEvent(new ActivityAsyncPendingEvent(pending.token, pending.operationId, pending.workflowId, pending.activityName, pending.attempt));
|
|
61
|
-
}
|
|
62
30
|
export async function parkDeferredAsyncActivity(internals, deferral, details, callbacks) {
|
|
63
31
|
const queuedResolution = takePendingAsyncActivityResolution(internals, details.workflowId, deferral.token);
|
|
64
32
|
if (queuedResolution !== void 0) {
|
|
65
|
-
deliverPendingAsyncActivityResolution(details.workflowId, queuedResolution, callbacks);
|
|
33
|
+
deliverPendingAsyncActivityResolution(internals, details.workflowId, queuedResolution, callbacks);
|
|
66
34
|
return new Promise(() => {});
|
|
67
35
|
}
|
|
68
36
|
await registerPendingAsyncActivity(internals, {
|
|
@@ -72,64 +40,31 @@ export async function parkDeferredAsyncActivity(internals, deferral, details, ca
|
|
|
72
40
|
});
|
|
73
41
|
return new Promise(() => {});
|
|
74
42
|
}
|
|
75
|
-
|
|
76
|
-
for await (const [, bytes] of internals.storage.scan(ASYNC_ACTIVITY_KEY_PREFIX)) {
|
|
77
|
-
const decoded = decode(bytes);
|
|
78
|
-
if (!isPersistedAsyncActivity(decoded))
|
|
79
|
-
continue;
|
|
80
|
-
internals.pendingAsyncActivities.set(decoded.token, {
|
|
81
|
-
token: decoded.token,
|
|
82
|
-
workflowId: decoded.workflowId,
|
|
83
|
-
activityName: decoded.activityName,
|
|
84
|
-
operationId: decoded.operationId,
|
|
85
|
-
step: decoded.step,
|
|
86
|
-
attempt: decoded.attempt,
|
|
87
|
-
createdAt: decoded.createdAt
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
async function consumePendingAsyncActivity(internals, token) {
|
|
43
|
+
async function consumePendingAsyncActivity(internals, token, outcome) {
|
|
92
44
|
const pending = internals.pendingAsyncActivities.get(token);
|
|
93
45
|
if (!pending)
|
|
94
46
|
throw new AsyncActivityTokenNotFoundError(token);
|
|
95
47
|
internals.pendingAsyncActivities.delete(token);
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
48
|
+
try {
|
|
49
|
+
await commitFencedEngineWrite(internals, buildAsyncActivityAcknowledgementOperations(pending, outcome), [], () => Error(`Async activity acknowledgement for token "${token}" lost its precondition.`));
|
|
50
|
+
} catch (error) {
|
|
51
|
+
internals.pendingAsyncActivities.set(token, pending);
|
|
52
|
+
throw error;
|
|
53
|
+
}
|
|
100
54
|
return pending;
|
|
101
55
|
}
|
|
102
|
-
function
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
internals.pendingAsyncActivityResolutions.set(workflowId, queued);
|
|
110
|
-
}
|
|
111
|
-
function takePendingAsyncActivityResolution(internals, workflowId, token) {
|
|
112
|
-
internals.pendingAsyncActivityResolutions ??= new Map;
|
|
113
|
-
const queued = internals.pendingAsyncActivityResolutions.get(workflowId);
|
|
114
|
-
if (queued === void 0)
|
|
115
|
-
return;
|
|
116
|
-
const index = queued.findIndex((resolution) => resolution.token === token);
|
|
117
|
-
if (index === -1)
|
|
118
|
-
return;
|
|
119
|
-
const resolution = queued[index];
|
|
120
|
-
if (resolution === void 0)
|
|
121
|
-
return;
|
|
122
|
-
queued.splice(index, 1);
|
|
123
|
-
if (queued.length === 0)
|
|
124
|
-
internals.pendingAsyncActivityResolutions.delete(workflowId);
|
|
125
|
-
return resolution;
|
|
126
|
-
}
|
|
127
|
-
function deliverPendingAsyncActivityResolution(workflowId, resolution, callbacks) {
|
|
56
|
+
function deliverPendingAsyncActivityResolution(internals, workflowId, resolution, callbacks) {
|
|
57
|
+
stageAtomicWorkflowCommitSideEffects(internals, workflowId, {
|
|
58
|
+
conditions: [],
|
|
59
|
+
operations: [
|
|
60
|
+
{ type: "delete", key: KEYS.asyncActivityResolution(workflowId, resolution.token) }
|
|
61
|
+
]
|
|
62
|
+
});
|
|
128
63
|
callbacks.finalizeTimeline(workflowId, resolution.timelineStatus, resolution.timelineOutput);
|
|
129
64
|
callbacks.feedOperationResult(workflowId, resolution.outcome, resolution.originalReason);
|
|
130
65
|
}
|
|
131
66
|
async function resolvePendingAsyncActivity(internals, token, outcome, callbacks, originalReason) {
|
|
132
|
-
const pending = await consumePendingAsyncActivity(internals, token), timelineOutput = outcome.status === "completed" ? outcome.value : outcome.error, resolution = {
|
|
67
|
+
const pending = await consumePendingAsyncActivity(internals, token, outcome), timelineOutput = outcome.status === "completed" ? outcome.value : outcome.error, resolution = {
|
|
133
68
|
token,
|
|
134
69
|
outcome,
|
|
135
70
|
timelineStatus: outcome.status,
|
|
@@ -140,7 +75,7 @@ async function resolvePendingAsyncActivity(internals, token, outcome, callbacks,
|
|
|
140
75
|
queuePendingAsyncActivityResolution(internals, pending.workflowId, resolution);
|
|
141
76
|
return;
|
|
142
77
|
}
|
|
143
|
-
deliverPendingAsyncActivityResolution(pending.workflowId, resolution, callbacks);
|
|
78
|
+
deliverPendingAsyncActivityResolution(internals, pending.workflowId, resolution, callbacks);
|
|
144
79
|
}
|
|
145
80
|
export async function completeAsyncActivity(internals, token, result, callbacks) {
|
|
146
81
|
assertPayloadWithinLimit(result, internals.options.payloadSizePolicy.maxBytes, "activity result");
|