@lostgradient/weft 0.24.0 → 0.24.2
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 +2 -2
- package/dist/cli/conformance.js +5 -2
- package/dist/cli/generated/operation-catalog.snapshot.json +95 -1
- package/dist/cli/generated/operation-client.generated.d.ts +28 -2
- package/dist/cli/generated/operation-client.generated.js +2 -0
- package/dist/cli/parse-schedule-arguments.js +15 -3
- package/dist/cli/schedule.js +2 -1
- package/dist/cli/types.d.ts +2 -1
- package/dist/client/http-client-requests.js +6 -9
- package/dist/client/start-body.js +1 -0
- package/dist/core/catalog/index.d.ts +2 -2
- package/dist/core/catalog/index.js +9 -2
- package/dist/core/catalog/reference-counts.d.ts +29 -14
- package/dist/core/catalog/removal.d.ts +63 -10
- package/dist/core/catalog/removal.js +18 -2
- package/dist/core/catalog/storage-io.d.ts +23 -0
- package/dist/core/catalog/storage-io.js +1 -1
- package/dist/core/engine/activity-resolution.js +17 -17
- package/dist/core/engine/bulk-operations-purge.d.ts +1 -1
- package/dist/core/engine/bulk-operations-purge.js +17 -22
- package/dist/core/engine/bulk-operations-retry.d.ts +24 -0
- package/dist/core/engine/bulk-operations-retry.js +190 -0
- package/dist/core/engine/bulk-operations-shared.d.ts +18 -0
- package/dist/core/engine/bulk-operations-shared.js +14 -0
- package/dist/core/engine/bulk-operations.d.ts +3 -2
- package/dist/core/engine/bulk-operations.js +10 -169
- package/dist/core/engine/callback-creators-bundles.js +5 -3
- package/dist/core/engine/callback-creators-core.js +9 -1
- package/dist/core/engine/callback-creators-schedule.js +2 -2
- package/dist/core/engine/catalog-readiness.js +2 -0
- package/dist/core/engine/catalog-removal.d.ts +107 -3
- package/dist/core/engine/catalog-removal.js +66 -13
- package/dist/core/engine/catalog-tombstone-recovery.d.ts +56 -0
- package/dist/core/engine/catalog-tombstone-recovery.js +39 -0
- package/dist/core/engine/child-workflow.d.ts +13 -1
- package/dist/core/engine/child-workflow.js +22 -4
- package/dist/core/engine/constraints.js +5 -1
- package/dist/core/engine/construction.d.ts +1 -1
- package/dist/core/engine/decode-revision.d.ts +32 -0
- package/dist/core/engine/decode-revision.js +9 -0
- package/dist/core/engine/disposal.d.ts +6 -2
- package/dist/core/engine/disposal.js +24 -10
- package/dist/core/engine/dynamic-source-errors.d.ts +81 -0
- package/dist/core/engine/dynamic-source-errors.js +25 -0
- package/dist/core/engine/dynamic-source-execution.d.ts +173 -0
- package/dist/core/engine/dynamic-source-execution.js +108 -0
- package/dist/core/engine/engine-internal-types.d.ts +16 -0
- package/dist/core/engine/engine-workflows-namespace.d.ts +10 -0
- package/dist/core/engine/engine-workflows-namespace.js +3 -1
- package/dist/core/engine/generation-codec.d.ts +22 -0
- package/dist/core/engine/generation-codec.js +2 -0
- package/dist/core/engine/index.d.ts +18 -10
- package/dist/core/engine/index.js +22 -11
- package/dist/core/engine/inline-launch-queue.js +1 -1
- package/dist/core/engine/internals.d.ts +26 -30
- package/dist/core/engine/lifecycle/checkpoint-launch.d.ts +29 -0
- package/dist/core/engine/lifecycle/checkpoint-launch.js +75 -0
- package/dist/core/engine/lifecycle/delayed-start-registration.d.ts +30 -0
- package/dist/core/engine/lifecycle/delayed-start-registration.js +11 -0
- package/dist/core/engine/lifecycle/fork-helpers.d.ts +33 -1
- package/dist/core/engine/lifecycle/fork-helpers.js +3 -1
- package/dist/core/engine/lifecycle/recovery-isolation.d.ts +20 -0
- package/dist/core/engine/lifecycle/recovery-isolation.js +26 -0
- package/dist/core/engine/lifecycle/recovery-revision-groups.d.ts +75 -0
- package/dist/core/engine/lifecycle/recovery-revision-groups.js +64 -0
- package/dist/core/engine/lifecycle/resume-body.d.ts +44 -0
- package/dist/core/engine/lifecycle/resume-body.js +211 -0
- package/dist/core/engine/lifecycle/resume-generation-guard.d.ts +58 -0
- package/dist/core/engine/lifecycle/resume-generation-guard.js +11 -0
- package/dist/core/engine/lifecycle/resume.d.ts +46 -3
- package/dist/core/engine/lifecycle/resume.js +21 -201
- package/dist/core/engine/lifecycle/shared.d.ts +43 -0
- package/dist/core/engine/lifecycle/standalone-claim-acquire.d.ts +80 -2
- package/dist/core/engine/lifecycle/standalone-claim-acquire.js +20 -4
- package/dist/core/engine/lifecycle/start-commit-errors.d.ts +12 -0
- package/dist/core/engine/lifecycle/start-commit-errors.js +6 -0
- package/dist/core/engine/lifecycle/start-commit.d.ts +24 -7
- package/dist/core/engine/lifecycle/start-commit.js +57 -15
- package/dist/core/engine/lifecycle/start-exec.d.ts +18 -2
- package/dist/core/engine/lifecycle/start-exec.js +7 -5
- package/dist/core/engine/lifecycle/start-or-signal-create.js +1 -3
- package/dist/core/engine/lifecycle/start-or-signal-resolution.d.ts +8 -2
- package/dist/core/engine/lifecycle/start-or-signal-resolution.js +11 -3
- package/dist/core/engine/lifecycle/start-or-signal.js +1 -1
- package/dist/core/engine/lifecycle/start-precondition-attribution.d.ts +55 -0
- package/dist/core/engine/lifecycle/start-precondition-attribution.js +13 -0
- package/dist/core/engine/lifecycle/start-revision-resolution.d.ts +34 -0
- package/dist/core/engine/lifecycle/start-revision-resolution.js +11 -0
- package/dist/core/engine/lifecycle/start-schedule-timing.d.ts +11 -0
- package/dist/core/engine/lifecycle/start-schedule-timing.js +21 -0
- package/dist/core/engine/lifecycle/start-state.d.ts +16 -0
- package/dist/core/engine/lifecycle/start-state.js +60 -0
- package/dist/core/engine/lifecycle/start-terminal-conflict-purge.d.ts +146 -4
- package/dist/core/engine/lifecycle/start-terminal-conflict-purge.js +33 -4
- package/dist/core/engine/lifecycle/start.d.ts +54 -7
- package/dist/core/engine/lifecycle/start.js +53 -90
- package/dist/core/engine/lifecycle/transition.d.ts +12 -4
- package/dist/core/engine/lifecycle/transition.js +40 -95
- package/dist/core/engine/lifecycle.d.ts +5 -2
- package/dist/core/engine/lifecycle.js +7 -6
- package/dist/core/engine/listing.js +15 -1
- package/dist/core/engine/memo-durable-activity.js +4 -1
- package/dist/core/engine/nonterminal-revision-count.d.ts +25 -0
- package/dist/core/engine/nonterminal-revision-count.js +16 -0
- package/dist/core/engine/operations-time.d.ts +5 -23
- package/dist/core/engine/operations-time.js +13 -11
- package/dist/core/engine/ownership-bootstrap.d.ts +1 -1
- package/dist/core/engine/pinned-schedule-revision-count.d.ts +26 -0
- package/dist/core/engine/pinned-schedule-revision-count.js +19 -0
- package/dist/core/engine/pinned-schedule-revision.d.ts +76 -0
- package/dist/core/engine/pinned-schedule-revision.js +53 -0
- package/dist/core/engine/registration.d.ts +30 -0
- package/dist/core/engine/registration.js +17 -2
- package/dist/core/engine/retention.js +9 -2
- package/dist/core/engine/revision-errors.d.ts +71 -0
- package/dist/core/engine/revision-errors.js +13 -0
- package/dist/core/engine/schedule-overlap.js +2 -1
- package/dist/core/engine/schedule-revision-fire.d.ts +17 -0
- package/dist/core/engine/schedule-revision-fire.js +3 -0
- package/dist/core/engine/schedule-run.d.ts +10 -0
- package/dist/core/engine/schedule-run.js +2 -1
- package/dist/core/engine/schedules.d.ts +11 -1
- package/dist/core/engine/schedules.js +28 -9
- package/dist/core/engine/source-diagnostics.d.ts +76 -0
- package/dist/core/engine/source-diagnostics.js +105 -0
- package/dist/core/engine/source-registration.js +4 -2
- package/dist/core/engine/source-resolution.d.ts +25 -9
- package/dist/core/engine/source-resolution.js +49 -14
- package/dist/core/engine/source-runtime-state.d.ts +92 -0
- package/dist/core/engine/source-runtime-state.js +36 -0
- package/dist/core/engine/storage-io.d.ts +19 -2
- package/dist/core/engine/storage-io.js +21 -2
- package/dist/core/engine/termination/complete.js +1 -1
- package/dist/core/engine/termination/finalizer-registration.d.ts +18 -0
- package/dist/core/engine/termination/finalizer-registration.js +21 -0
- package/dist/core/engine/termination/finalizer.d.ts +16 -19
- package/dist/core/engine/termination/finalizer.js +3 -3
- package/dist/core/engine/termination/suspend.js +3 -0
- package/dist/core/engine/time-operation-callbacks.d.ts +32 -0
- package/dist/core/engine/time-operation-callbacks.js +0 -0
- package/dist/core/engine/validation/schedule-cadence.d.ts +16 -0
- package/dist/core/engine/validation/schedule-cadence.js +20 -0
- package/dist/core/engine/validation/schedule-options.d.ts +4 -1
- package/dist/core/engine/validation/schedule-options.js +14 -0
- package/dist/core/engine/validation/schedule-revision.d.ts +24 -0
- package/dist/core/engine/validation/schedule-revision.js +21 -0
- package/dist/core/engine/validation/schedule-warnings.d.ts +11 -0
- package/dist/core/engine/validation/schedule-warnings.js +5 -0
- package/dist/core/engine/validation/schedule.d.ts +29 -4
- package/dist/core/engine/validation/schedule.js +19 -36
- package/dist/core/engine/validation.js +13 -17
- package/dist/core/engine/workflow-claim-reclaim-target.d.ts +1 -1
- package/dist/core/engine/workflow-claim-reclaim-target.js +22 -8
- package/dist/core/engine/workflow-claim-registry.d.ts +79 -75
- package/dist/core/engine/workflow-claim-registry.js +15 -2
- package/dist/core/engine/workflow-generation-fence.d.ts +74 -0
- package/dist/core/engine/workflow-generation-fence.js +19 -0
- package/dist/core/engine/workflow-retention-deadline.d.ts +16 -0
- package/dist/core/engine/workflow-retention-deadline.js +33 -0
- package/dist/core/events/event-map.d.ts +5 -0
- package/dist/core/events/index.d.ts +1 -0
- package/dist/core/events/index.js +1 -0
- package/dist/core/events/workflow-source-events.d.ts +102 -0
- package/dist/core/events/workflow-source-events.js +57 -0
- package/dist/core/execution-strategy.d.ts +7 -0
- package/dist/core/inline-execution-strategy.context-options.d.ts +1 -1
- package/dist/core/inline-execution-strategy.js +1 -1
- package/dist/core/start-workflow-validation.d.ts +15 -0
- package/dist/core/start-workflow-validation.js +11 -1
- package/dist/core/types/checkpoint.d.ts +14 -0
- package/dist/core/types/schedules.d.ts +52 -1
- package/dist/core/types/state.d.ts +16 -0
- package/dist/core/weft-error.d.ts +1 -1
- package/dist/core/weft-error.js +4 -1
- package/dist/core/worker-execution-strategy.d.ts +1 -0
- package/dist/core/worker-execution-strategy.js +13 -1
- package/dist/core/worker-fault-handling.d.ts +10 -0
- package/dist/core/worker-fault-handling.js +1 -0
- package/dist/core/worker-inbound-message.d.ts +1 -0
- package/dist/core/worker-inbound-message.js +1 -0
- package/dist/core/worker-protocol-guard.js +4 -0
- package/dist/core/worker-protocol.d.ts +7 -0
- package/dist/core/worker-protocol.js +2 -1
- package/dist/core/worker-turn-watchdog.d.ts +8 -1
- package/dist/core/worker-turn-watchdog.js +3 -2
- package/dist/core/workflow-identifiers.d.ts +37 -0
- package/dist/core/workflow-identifiers.js +19 -1
- package/dist/diagnostics/format.js +5 -0
- package/dist/diagnostics/types.d.ts +24 -0
- package/dist/diagnostics/version-check.js +8 -2
- package/dist/http.js +2 -2
- package/dist/index.d.ts +3 -3
- package/dist/index.js +7 -0
- package/dist/indexeddb.js +1 -1
- package/dist/json-schema.js +3 -3
- package/dist/server/fault-to-json-rpc.js +2 -1
- package/dist/server/fleet-event-feed.js +6 -6
- package/dist/server/index.d.ts +11 -0
- package/dist/server/operation-fault.d.ts +2 -0
- package/dist/server/operation-fault.js +2 -1
- package/dist/server/operations/create-schedule.d.ts +2 -0
- package/dist/server/operations/create-schedule.js +10 -6
- package/dist/server/operations/get-catalog-diagnostics.d.ts +28 -0
- package/dist/server/operations/get-catalog-diagnostics.js +10 -2
- package/dist/server/operations/get-task-detail-schema.d.ts +8 -0
- package/dist/server/operations/get-task-detail-schema.js +1 -0
- package/dist/server/operations/get-task-detail.d.ts +8 -0
- package/dist/server/operations/get-task-detail.js +1 -0
- package/dist/server/operations/get-task-diagnostics.d.ts +4 -4
- package/dist/server/operations/preload-workflow-revision.d.ts +28 -0
- package/dist/server/operations/preload-workflow-revision.js +60 -0
- package/dist/server/operations/schedule-faults.d.ts +1 -0
- package/dist/server/operations/schedule-faults.js +32 -4
- package/dist/server/operations/schedule-rest-body.d.ts +1 -0
- package/dist/server/operations/schedule-rest-body.js +2 -1
- package/dist/server/operations/static-registrations.js +6 -0
- package/dist/server/operations/update-schedule.d.ts +2 -0
- package/dist/server/operations/update-schedule.js +4 -2
- package/dist/server/operations/workflow-catalog-operation-helpers.js +27 -0
- package/dist/server/rest-binding.d.ts +11 -0
- package/dist/server/runtime/task-dispatch-envelope.d.ts +41 -0
- package/dist/server/runtime/task-dispatch-envelope.js +54 -0
- package/dist/server/runtime/task-dispatch-revision.d.ts +29 -0
- package/dist/server/runtime/task-dispatch-revision.js +13 -0
- package/dist/server/runtime/task-dispatch.d.ts +3 -1
- package/dist/server/runtime/task-dispatch.js +20 -44
- package/dist/server/runtime/task-ledger-recovery.js +1 -1
- package/dist/server/runtime/task-ledger-runtime.d.ts +14 -2
- package/dist/server/runtime/task-ledger-runtime.js +5 -3
- package/dist/server/runtime/task-polling.js +9 -3
- package/dist/server/runtime/task-reconciliation.js +2 -1
- package/dist/server/runtime/websocket-worker.js +9 -0
- package/dist/server/task-ledger-codec.d.ts +28 -0
- package/dist/server/task-ledger-codec.js +7 -1
- package/dist/server/task-ledger-transition-helpers.js +1 -0
- package/dist/server/task-ledger-types.d.ts +9 -0
- package/dist/server/task-ledger.d.ts +1 -1
- package/dist/server/task-ledger.js +3 -1
- package/dist/server/task-queue-types.d.ts +2 -0
- package/dist/storage/bun-sql.js +135 -100
- package/dist/storage/catalog-keys.d.ts +19 -0
- package/dist/storage/catalog-keys.js +3 -1
- package/dist/storage/compressed-storage.js +1 -1
- package/dist/storage/generation-keys.d.ts +52 -0
- package/dist/storage/generation-keys.js +4 -0
- package/dist/storage/index.d.ts +76 -63
- package/dist/storage/interface.d.ts +24 -230
- package/dist/storage/interface.js +1 -1
- package/dist/storage/key-prefixes.d.ts +1 -1
- package/dist/storage/key-prefixes.js +2 -0
- package/dist/storage/lease-keys.d.ts +48 -0
- package/dist/storage/lease-keys.js +8 -0
- package/dist/storage/lmdb.d.ts +30 -2
- package/dist/storage/lmdb.js +1 -1
- package/dist/storage/memory.js +1 -1
- package/dist/storage/neon.js +3 -3
- package/dist/storage/node-sqlite.js +135 -100
- package/dist/storage/postgres.js +3 -3
- package/dist/storage/resolve.js +1 -1
- package/dist/storage/scoped-storage.js +1 -1
- package/dist/storage/signal-keys.d.ts +23 -0
- package/dist/storage/signal-keys.js +9 -0
- package/dist/storage/testing.js +1 -1
- package/dist/storage/turso.js +2 -2
- package/dist/storage/workflow-lifecycle-keys.d.ts +128 -0
- package/dist/storage/workflow-lifecycle-keys.js +46 -0
- package/dist/storage/workflow-record-keys.d.ts +98 -0
- package/dist/storage/workflow-record-keys.js +47 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/web-extension.js +1 -1
- package/dist/worker/protocol-messages.d.ts +17 -0
- package/dist/worker/protocol-schemas.d.ts +32 -0
- package/dist/worker/protocol-schemas.js +7 -3
- package/dist/worker/protocol-task-result.js +35 -3
- package/dist/worker/protocol.js +1 -1
- package/dist/worker/registry/types.d.ts +2 -0
- package/dist/worker/registry.d.ts +1 -1
- package/dist/worker/registry.js +3 -1
- package/dist/workers/workflow-runner.d.ts +9 -0
- package/dist/workers/workflow-runner.js +9 -2
- package/dist/workers/workflow-worker-entry.js +9 -4
- package/package.json +2 -2
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { isJSONValue } from "../../core/json.js";
|
|
2
1
|
import { buildWorkerExecutionIdentity } from "../../worker/manifest/execution-identity.js";
|
|
3
2
|
import { evictOldestAffinityEntries } from "../runtime-helpers.js";
|
|
4
3
|
import {
|
|
@@ -7,9 +6,14 @@ import {
|
|
|
7
6
|
} from "../task-ledger-transitions.js";
|
|
8
7
|
import {
|
|
9
8
|
decodeRemoteTaskRecord,
|
|
10
|
-
REMOTE_TASK_RECORD_VERSION,
|
|
11
9
|
taskLedgerKey
|
|
12
10
|
} from "../task-ledger.js";
|
|
11
|
+
import {
|
|
12
|
+
assertFreshDispatchOperationIdAdmissible,
|
|
13
|
+
awaitTaskLedgerRecoveryReady,
|
|
14
|
+
buildCreateQueuedInput
|
|
15
|
+
} from "./task-dispatch-envelope.js";
|
|
16
|
+
import { assertDispatchTargetsFreshRevision } from "./task-dispatch-revision.js";
|
|
13
17
|
import { commitTaskLedgerTransition } from "./task-ledger-runtime.js";
|
|
14
18
|
import {
|
|
15
19
|
recordTaskBacklogMetric,
|
|
@@ -27,7 +31,7 @@ export function scheduleDelayedDispatch(context, options, task, delay) {
|
|
|
27
31
|
return;
|
|
28
32
|
const timer = setTimeout(() => {
|
|
29
33
|
context.pendingTimers.delete(timer);
|
|
30
|
-
dispatchTaskImpl(context, options, task).catch((err) => console.error(`[weft] Delayed redispatch failed for "${task.operationId}":`, err));
|
|
34
|
+
dispatchTaskImpl(context, options, task, { redispatch: !0 }).catch((err) => console.error(`[weft] Delayed redispatch failed for "${task.operationId}":`, err));
|
|
31
35
|
}, delay);
|
|
32
36
|
context.pendingTimers.add(timer);
|
|
33
37
|
}
|
|
@@ -65,33 +69,6 @@ function recordDispatchOutcome(context, task, workerId) {
|
|
|
65
69
|
operationIds.add(task.operationId);
|
|
66
70
|
context.operationToWorkflow.set(task.operationId, task.workflowId);
|
|
67
71
|
}
|
|
68
|
-
function buildOptionalCreateQueuedFields(task) {
|
|
69
|
-
return {
|
|
70
|
-
...task.workflowId !== void 0 ? { workflowId: task.workflowId } : {},
|
|
71
|
-
...task.workflowExecutionToken !== void 0 ? { workflowExecutionToken: task.workflowExecutionToken } : {},
|
|
72
|
-
...task.priority !== void 0 ? { priority: task.priority } : {},
|
|
73
|
-
...task.fairShareKey !== void 0 ? { fairShareKey: task.fairShareKey } : {},
|
|
74
|
-
...task.sticky && task.workflowId !== void 0 ? { stickyWorkflowId: task.workflowId } : {},
|
|
75
|
-
...task.retryPolicy !== void 0 ? { retryPolicy: task.retryPolicy } : {}
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
function buildCreateQueuedInput(task, queue, visibilityTimeout) {
|
|
79
|
-
const input = task.input === void 0 ? null : task.input;
|
|
80
|
-
if (!isJSONValue(input))
|
|
81
|
-
throw Error(`TaskDispatch for operation "${task.operationId}" has a non-JSON-serializable "input" \u2014 the durable task ledger requires JSON-safe input.`);
|
|
82
|
-
return {
|
|
83
|
-
recordVersion: REMOTE_TASK_RECORD_VERSION,
|
|
84
|
-
operationId: task.operationId,
|
|
85
|
-
workflowType: task.workflowType,
|
|
86
|
-
activityName: task.activityName,
|
|
87
|
-
queue,
|
|
88
|
-
input,
|
|
89
|
-
headers: task.headers ?? {},
|
|
90
|
-
visibilityTimeoutMilliseconds: visibilityTimeout,
|
|
91
|
-
createdAt: Date.now(),
|
|
92
|
-
...buildOptionalCreateQueuedFields(task)
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
72
|
function buildCreateThenClaimTransition(createInput, claimInput) {
|
|
96
73
|
return (current, now) => {
|
|
97
74
|
let queuedRecord;
|
|
@@ -114,7 +91,7 @@ function bareActivityName(qualifiedActivityName) {
|
|
|
114
91
|
const dotIndex = qualifiedActivityName.indexOf(".");
|
|
115
92
|
return dotIndex === -1 ? qualifiedActivityName : qualifiedActivityName.slice(dotIndex + 1);
|
|
116
93
|
}
|
|
117
|
-
async function selectAndReserveWorker(context, options, task, queue, visibilityTimeout) {
|
|
94
|
+
async function selectAndReserveWorker(context, options, task, queue, visibilityTimeout, revisionFenceConditions) {
|
|
118
95
|
const routingOptions = buildRoutingOptions(context, task, queue), worker = context.registry.findWorker(task.activityName, routingOptions);
|
|
119
96
|
if (!worker)
|
|
120
97
|
return !1;
|
|
@@ -128,7 +105,7 @@ async function selectAndReserveWorker(context, options, task, queue, visibilityT
|
|
|
128
105
|
workflowType: task.workflowType,
|
|
129
106
|
activityName: bareActivityName(task.activityName)
|
|
130
107
|
});
|
|
131
|
-
context.registry.assignTask(worker.id, task.operationId, visibilityTimeout, task.fairShareKey, attemptToken);
|
|
108
|
+
context.registry.assignTask(worker.id, task.operationId, visibilityTimeout, task.fairShareKey, attemptToken, task.workflowRevision);
|
|
132
109
|
let result;
|
|
133
110
|
try {
|
|
134
111
|
result = await commitTaskLedgerTransition(options.engine.storage, task.operationId, buildCreateThenClaimTransition(createInput, {
|
|
@@ -136,7 +113,7 @@ async function selectAndReserveWorker(context, options, task, queue, visibilityT
|
|
|
136
113
|
workerSessionId: worker.id,
|
|
137
114
|
...executionIdentity !== void 0 ? { executionIdentity } : {},
|
|
138
115
|
leaseDurationMilliseconds: visibilityTimeout
|
|
139
|
-
}), 1);
|
|
116
|
+
}), 1, revisionFenceConditions);
|
|
140
117
|
} catch (error) {
|
|
141
118
|
context.registry.releaseReservation(task.operationId);
|
|
142
119
|
throw error;
|
|
@@ -159,6 +136,7 @@ async function selectAndReserveWorker(context, options, task, queue, visibilityT
|
|
|
159
136
|
...task.workflowExecutionToken !== void 0 && {
|
|
160
137
|
workflowExecutionToken: task.workflowExecutionToken
|
|
161
138
|
},
|
|
139
|
+
...task.workflowRevision !== void 0 && { workflowRevision: task.workflowRevision },
|
|
162
140
|
...task.headers ? { headers: task.headers } : {}
|
|
163
141
|
}));
|
|
164
142
|
recordTaskQueueLatencyMetric(context.metricsCollector, {
|
|
@@ -169,11 +147,11 @@ async function selectAndReserveWorker(context, options, task, queue, visibilityT
|
|
|
169
147
|
recordDispatchOutcome(context, task, worker.id);
|
|
170
148
|
return !0;
|
|
171
149
|
}
|
|
172
|
-
async function enqueueTaskForLongPoll(context, options, task, queue, visibilityTimeout, resolvedPriority) {
|
|
150
|
+
async function enqueueTaskForLongPoll(context, options, task, queue, visibilityTimeout, resolvedPriority, revisionFenceConditions) {
|
|
173
151
|
const storage = options.engine.storage, createInput = buildCreateQueuedInput(task, queue, visibilityTimeout), rawExisting = await storage.get(taskLedgerKey(task.operationId)), current = decodeRemoteTaskRecord(rawExisting);
|
|
174
152
|
let queuedRecord;
|
|
175
153
|
if (current === null) {
|
|
176
|
-
const result = await commitTaskLedgerTransition(storage, task.operationId, (freshCurrent, now) => createQueued(freshCurrent, createInput, now), 1);
|
|
154
|
+
const result = await commitTaskLedgerTransition(storage, task.operationId, (freshCurrent, now) => createQueued(freshCurrent, createInput, now), 1, revisionFenceConditions);
|
|
177
155
|
if (!result.ok) {
|
|
178
156
|
const raced = decodeRemoteTaskRecord(await storage.get(taskLedgerKey(task.operationId)));
|
|
179
157
|
if (raced === null || raced.state !== "queued")
|
|
@@ -194,6 +172,7 @@ async function enqueueTaskForLongPoll(context, options, task, queue, visibilityT
|
|
|
194
172
|
visibilityTimeout,
|
|
195
173
|
workflowId: task.workflowId,
|
|
196
174
|
workflowExecutionToken: task.workflowExecutionToken,
|
|
175
|
+
workflowRevision: queuedRecord.workflowRevision,
|
|
197
176
|
firstQueuedAt: queuedRecord.firstQueuedAt,
|
|
198
177
|
lastQueuedAt: queuedRecord.lastQueuedAt,
|
|
199
178
|
lastDispatchedAt: queuedRecord.lastDispatchedAt,
|
|
@@ -206,23 +185,20 @@ async function enqueueTaskForLongPoll(context, options, task, queue, visibilityT
|
|
|
206
185
|
recordTaskBacklogMetric(context.metricsCollector, context.taskQueue);
|
|
207
186
|
return enqueued;
|
|
208
187
|
}
|
|
209
|
-
export async function dispatchTaskImpl(context, options, task) {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
} catch (error) {
|
|
213
|
-
throw Error(`Cannot dispatch task "${task.operationId}" \u2014 startup task-ledger recovery failed: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
214
|
-
}
|
|
188
|
+
export async function dispatchTaskImpl(context, options, task, { redispatch = !1 } = {}) {
|
|
189
|
+
await awaitTaskLedgerRecoveryReady(context, task);
|
|
190
|
+
assertFreshDispatchOperationIdAdmissible(task, redispatch);
|
|
215
191
|
if (!task.workflowType)
|
|
216
192
|
throw Error(`TaskDispatch for operation "${task.operationId}" is missing required field "workflowType".`);
|
|
217
|
-
const dotIndex = task.activityName.indexOf(".");
|
|
193
|
+
const revisionFenceConditions = await assertDispatchTargetsFreshRevision(options, task), dotIndex = task.activityName.indexOf(".");
|
|
218
194
|
if (dotIndex !== -1 && task.activityName.slice(0, dotIndex) !== task.workflowType)
|
|
219
195
|
throw Error(`TaskDispatch for operation "${task.operationId}" has activityName "${task.activityName}" whose qualifier does not match workflowType "${task.workflowType}".`);
|
|
220
196
|
const queue = task.queue ?? "default", visibilityTimeout = clampVisibilityTimeout(task.visibilityTimeout), resolvedPriority = resolveTaskPriority(context, options, task);
|
|
221
197
|
if (!validateTaskEnvelope(context, task))
|
|
222
198
|
return !1;
|
|
223
|
-
if (await selectAndReserveWorker(context, options, task, queue, visibilityTimeout))
|
|
199
|
+
if (await selectAndReserveWorker(context, options, task, queue, visibilityTimeout, revisionFenceConditions))
|
|
224
200
|
return !0;
|
|
225
|
-
return enqueueTaskForLongPoll(context, options, task, queue, visibilityTimeout, resolvedPriority);
|
|
201
|
+
return enqueueTaskForLongPoll(context, options, task, queue, visibilityTimeout, resolvedPriority, revisionFenceConditions);
|
|
226
202
|
}
|
|
227
203
|
export function cancelTask(context, operationId) {
|
|
228
204
|
const task = context.registry.getTask(operationId);
|
|
@@ -16,7 +16,7 @@ function rebuildWorkflowIndex(context, operationId, workflowId) {
|
|
|
16
16
|
}
|
|
17
17
|
function rehydrateWorkerOwnership(context, record, now) {
|
|
18
18
|
const remaining = Math.max(0, record.leaseDeadline - now);
|
|
19
|
-
context.registry.assignTask(record.workerSessionId, record.operationId, remaining, record.fairShareKey, record.attemptToken);
|
|
19
|
+
context.registry.assignTask(record.workerSessionId, record.operationId, remaining, record.fairShareKey, record.attemptToken, record.workflowRevision);
|
|
20
20
|
const tracked = context.registry.getWorkerTasks(record.workerSessionId).find((task) => task.operationId === record.operationId);
|
|
21
21
|
if (tracked)
|
|
22
22
|
tracked.visibilityTimeout = record.visibilityTimeoutMilliseconds;
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
*
|
|
17
17
|
* @module server/runtime/task-ledger-runtime
|
|
18
18
|
*/
|
|
19
|
-
import { type Storage } from '../../storage/interface.ts';
|
|
19
|
+
import { type ConditionalBatchCondition, type Storage } from '../../storage/interface.ts';
|
|
20
20
|
import type { TaskLedgerPreconditionResult, TaskLedgerTransitionResult } from '../task-ledger-transitions.ts';
|
|
21
21
|
import { type RemoteTaskRecord } from '../task-ledger.ts';
|
|
22
22
|
export type TaskLedgerCommitResult<T extends RemoteTaskRecord> = Readonly<{
|
|
@@ -46,7 +46,19 @@ export type TaskLedgerDeleteResult = Readonly<{
|
|
|
46
46
|
* reflects reality and re-attempting the identical transition cannot change
|
|
47
47
|
* the outcome.
|
|
48
48
|
*/
|
|
49
|
-
export declare function commitTaskLedgerTransition<T extends RemoteTaskRecord>(storage: Storage, operationId: string, transitionFn: (current: RemoteTaskRecord | null, now: number) => TaskLedgerTransitionResult<T>, maxAttempts?: number
|
|
49
|
+
export declare function commitTaskLedgerTransition<T extends RemoteTaskRecord>(storage: Storage, operationId: string, transitionFn: (current: RemoteTaskRecord | null, now: number) => TaskLedgerTransitionResult<T>, maxAttempts?: number,
|
|
50
|
+
/**
|
|
51
|
+
* Extra same-transaction preconditions to fence the commit on — for
|
|
52
|
+
* example, "the target workflow's persisted state is still exactly the
|
|
53
|
+
* bytes read at dispatch time" (WFT-20's revision-staleness gate). Checked
|
|
54
|
+
* in the SAME `conditionalBatch` call as the ledger key's own CAS, so a
|
|
55
|
+
* concurrent write to any of these keys between read and commit loses the
|
|
56
|
+
* whole batch atomically, closing the gap a standalone pre-check
|
|
57
|
+
* (read-then-later-write, with unrelated work in between) cannot close.
|
|
58
|
+
* Re-supplied by the caller on each retry attempt since the caller, not
|
|
59
|
+
* this loop, owns re-reading whatever these conditions guard.
|
|
60
|
+
*/
|
|
61
|
+
additionalConditions?: readonly ConditionalBatchCondition[]): Promise<TaskLedgerCommitResult<T>>;
|
|
50
62
|
/**
|
|
51
63
|
* Read the current ledger record, check a delete-only precondition (WFT-24
|
|
52
64
|
* retention: {@link canDeleteRetainedTerminalTask}), and conditionally delete
|
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
storageConditionalBatch
|
|
3
|
+
} from "../../storage/interface.js";
|
|
2
4
|
import {
|
|
3
5
|
decodeRemoteTaskRecord,
|
|
4
6
|
encodeRemoteTaskRecord,
|
|
5
7
|
taskLedgerKey
|
|
6
8
|
} from "../task-ledger.js";
|
|
7
|
-
export async function commitTaskLedgerTransition(storage, operationId, transitionFn, maxAttempts = 1) {
|
|
9
|
+
export async function commitTaskLedgerTransition(storage, operationId, transitionFn, maxAttempts = 1, additionalConditions = []) {
|
|
8
10
|
const key = taskLedgerKey(operationId);
|
|
9
11
|
for (let attempt = 1;attempt <= maxAttempts; attempt++) {
|
|
10
12
|
const rawExisting = await storage.get(key), current = decodeRemoteTaskRecord(rawExisting), result = transitionFn(current, Date.now());
|
|
11
13
|
if (!result.ok)
|
|
12
14
|
return result;
|
|
13
|
-
if (await storageConditionalBatch(storage, [{ key, expectedValue: rawExisting }], [{ type: "put", key, value: encodeRemoteTaskRecord(result.nextRecord) }]))
|
|
15
|
+
if (await storageConditionalBatch(storage, [{ key, expectedValue: rawExisting }, ...additionalConditions], [{ type: "put", key, value: encodeRemoteTaskRecord(result.nextRecord) }]))
|
|
14
16
|
return { ok: !0, record: result.nextRecord };
|
|
15
17
|
}
|
|
16
18
|
return {
|
|
@@ -58,7 +58,8 @@ function validateTaskResultBody(body) {
|
|
|
58
58
|
workerId: typeof body.workerId === "string" ? body.workerId : void 0,
|
|
59
59
|
value: body.value,
|
|
60
60
|
error: typeof body.error === "string" ? body.error : void 0,
|
|
61
|
-
attemptToken: rawAttemptToken
|
|
61
|
+
attemptToken: rawAttemptToken,
|
|
62
|
+
workflowRevision: typeof body.workflowRevision === "string" ? body.workflowRevision : void 0
|
|
62
63
|
};
|
|
63
64
|
}
|
|
64
65
|
function isLongPollCompletionAuthorized(record, validated) {
|
|
@@ -68,7 +69,11 @@ function isLongPollCompletionAuthorized(record, validated) {
|
|
|
68
69
|
return !1;
|
|
69
70
|
if (validated.workerId === void 0 || record.workerSessionId !== validated.workerId)
|
|
70
71
|
return !1;
|
|
71
|
-
|
|
72
|
+
if (validated.attemptToken !== record.attemptToken)
|
|
73
|
+
return !1;
|
|
74
|
+
if (record.workflowRevision !== void 0 && validated.workflowRevision !== record.workflowRevision)
|
|
75
|
+
return !1;
|
|
76
|
+
return !0;
|
|
72
77
|
}
|
|
73
78
|
async function applyTaskResult(context, options, result) {
|
|
74
79
|
const { operationId, status, value, error } = result, committed = await commitTaskLedgerCompletion(options.engine.storage, {
|
|
@@ -155,7 +160,8 @@ export async function handleTaskPollRequest(context, options, request, url, prin
|
|
|
155
160
|
attemptToken: claim.attemptToken,
|
|
156
161
|
...task.workflowExecutionToken !== void 0 && {
|
|
157
162
|
workflowExecutionToken: task.workflowExecutionToken
|
|
158
|
-
}
|
|
163
|
+
},
|
|
164
|
+
...task.workflowRevision !== void 0 && { workflowRevision: task.workflowRevision }
|
|
159
165
|
});
|
|
160
166
|
}
|
|
161
167
|
return new Response(null, { status: 204 });
|
|
@@ -65,7 +65,8 @@ export function taskDispatchFromLedgerRecord(record) {
|
|
|
65
65
|
input: record.input,
|
|
66
66
|
queue: record.queue,
|
|
67
67
|
visibilityTimeout: record.visibilityTimeoutMilliseconds,
|
|
68
|
-
workflowExecutionToken: record.workflowExecutionToken
|
|
68
|
+
workflowExecutionToken: record.workflowExecutionToken,
|
|
69
|
+
workflowRevision: record.workflowRevision
|
|
69
70
|
};
|
|
70
71
|
if (record.workflowId !== void 0)
|
|
71
72
|
taskDispatch.workflowId = record.workflowId;
|
|
@@ -47,6 +47,15 @@ function onTaskResultMessage(context, options, ws, message, cleanupWorkflowIndex
|
|
|
47
47
|
});
|
|
48
48
|
return;
|
|
49
49
|
}
|
|
50
|
+
const inFlightTask = context.registry.getTask(operationId);
|
|
51
|
+
if (inFlightTask?.workflowRevision !== void 0 && message.workflowRevision !== inFlightTask.workflowRevision) {
|
|
52
|
+
sendWorkerProtocolMessage(ws, {
|
|
53
|
+
type: "protocolError",
|
|
54
|
+
code: "invalid_message",
|
|
55
|
+
message: `taskResult for operation "${operationId}" rejected \u2014 revision mismatch`
|
|
56
|
+
});
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
50
59
|
const resolvedStatus = resolveTaskResultStatus(message), payloadError = taskResultPayloadSizeError({
|
|
51
60
|
status: resolvedStatus,
|
|
52
61
|
...message.status === "completed" ? { value: message.value } : { error: message.error }
|
|
@@ -15,6 +15,34 @@
|
|
|
15
15
|
* @module server/task-ledger-codec
|
|
16
16
|
*/
|
|
17
17
|
import type { RemoteTaskCancelling, RemoteTaskCompleting, RemoteTaskDeadLettered, RemoteTaskLeased, RemoteTaskQueued, RemoteTaskRecord, RemoteTaskTerminal, RemoteTaskTerminalCancelled, RemoteTaskTerminalResolved, RemoteTaskTerminalRetryExhausted } from './task-ledger-types.ts';
|
|
18
|
+
/**
|
|
19
|
+
* Whether `value` is a valid `workflowRevision` per the durable task
|
|
20
|
+
* ledger's non-empty, bounded identifier contract — the same contract
|
|
21
|
+
* `decodeRemoteTaskRecord` enforces on read. Exported so dispatch-time
|
|
22
|
+
* callers (`task-dispatch.ts`) can reject an invalid caller-supplied
|
|
23
|
+
* revision before it reaches a ledger write, instead of writing a record
|
|
24
|
+
* that later fails to decode.
|
|
25
|
+
*/
|
|
26
|
+
export declare function isValidWorkflowRevision(value: unknown): value is string;
|
|
27
|
+
/**
|
|
28
|
+
* Whether `value` is a valid caller-facing task `operationId` — a non-empty,
|
|
29
|
+
* bounded identifier per the ledger's own contract, and not the exact string
|
|
30
|
+
* `.` or `..` (WFT-95). WHATWG URL path normalization collapses `.`/`..`
|
|
31
|
+
* path segments (and their percent-encoded forms) before `handleRequest()`
|
|
32
|
+
* ever sees `url.pathname`, so a REST route with a single trailing
|
|
33
|
+
* `:operationId` segment (e.g. `weft.tasks.get`'s
|
|
34
|
+
* `/v1/tasks/detail/:operationId`) can never address a record whose
|
|
35
|
+
* operationId is literally `.` or `..`. Exported so fresh-dispatch admission
|
|
36
|
+
* (`task-dispatch.ts`'s `dispatchTaskImpl`) can reject an invalid
|
|
37
|
+
* caller-supplied `operationId` before it ever reaches a ledger write,
|
|
38
|
+
* closing that URL-normalization quirk as an enforced admission-time
|
|
39
|
+
* guarantee instead of an assumption. Deliberately NOT applied when
|
|
40
|
+
* redispatching an already-decoded, previously persisted ledger record —
|
|
41
|
+
* see `dispatchTaskImpl`'s `redispatch` option — since such an id was valid
|
|
42
|
+
* under the pre-WFT-95 decode contract and may already be durably
|
|
43
|
+
* persisted. Does not reject an id that merely contains a dot character.
|
|
44
|
+
*/
|
|
45
|
+
export declare function isValidOperationId(value: unknown): value is string;
|
|
18
46
|
/** Bounded header map: at most {@link MAX_TASK_HEADER_COUNT} entries, each key/value at most {@link MAX_TASK_HEADER_VALUE_BYTES}. */
|
|
19
47
|
export declare function isValidTaskHeaders(value: unknown): value is Readonly<Record<string, string>>;
|
|
20
48
|
export declare function isRemoteTaskQueued(value: unknown): value is RemoteTaskQueued;
|
|
@@ -14,6 +14,12 @@ function isRecord(value) {
|
|
|
14
14
|
function isBoundedIdentifier(value, maxBytes = MAX_TASK_IDENTIFIER_BYTES) {
|
|
15
15
|
return typeof value === "string" && value.length > 0 && utf8ByteLength(value) <= maxBytes;
|
|
16
16
|
}
|
|
17
|
+
export function isValidWorkflowRevision(value) {
|
|
18
|
+
return isBoundedIdentifier(value);
|
|
19
|
+
}
|
|
20
|
+
export function isValidOperationId(value) {
|
|
21
|
+
return isBoundedIdentifier(value) && value !== "." && value !== "..";
|
|
22
|
+
}
|
|
17
23
|
function isBoundedOptionalIdentifier(value, maxBytes = MAX_TASK_IDENTIFIER_BYTES) {
|
|
18
24
|
return value === void 0 || isBoundedIdentifier(value, maxBytes);
|
|
19
25
|
}
|
|
@@ -86,7 +92,7 @@ function isOptionalExecutionIdentity(value) {
|
|
|
86
92
|
return value === void 0 || isValidExecutionIdentity(value);
|
|
87
93
|
}
|
|
88
94
|
function isValidTaskIdentityFields(value) {
|
|
89
|
-
return value.recordVersion === 1 && isBoundedIdentifier(value.operationId) && isBoundedOptionalIdentifier(value.workflowId) && isBoundedIdentifier(value.workflowType) && isBoundedOptionalIdentifier(value.workflowExecutionToken) && isBoundedIdentifier(value.activityName) && isBoundedIdentifier(value.queue);
|
|
95
|
+
return value.recordVersion === 1 && isBoundedIdentifier(value.operationId) && isBoundedOptionalIdentifier(value.workflowId) && isBoundedIdentifier(value.workflowType) && isBoundedOptionalIdentifier(value.workflowExecutionToken) && isBoundedOptionalIdentifier(value.workflowRevision) && isBoundedIdentifier(value.activityName) && isBoundedIdentifier(value.queue);
|
|
90
96
|
}
|
|
91
97
|
function isValidTaskRoutingFields(value) {
|
|
92
98
|
return isOptionalFiniteNumber(value.priority) && isBoundedOptionalIdentifier(value.fairShareKey) && isBoundedOptionalIdentifier(value.stickyWorkflowId) && isValidExecutionRequirement(value.executionRequirement);
|
|
@@ -5,6 +5,7 @@ export function pickBase(record) {
|
|
|
5
5
|
...record.workflowId !== void 0 ? { workflowId: record.workflowId } : {},
|
|
6
6
|
workflowType: record.workflowType,
|
|
7
7
|
...record.workflowExecutionToken !== void 0 ? { workflowExecutionToken: record.workflowExecutionToken } : {},
|
|
8
|
+
...record.workflowRevision !== void 0 ? { workflowRevision: record.workflowRevision } : {},
|
|
8
9
|
activityName: record.activityName,
|
|
9
10
|
queue: record.queue,
|
|
10
11
|
input: record.input,
|
|
@@ -48,6 +48,15 @@ export type RemoteTaskBase = Readonly<{
|
|
|
48
48
|
workflowId?: string;
|
|
49
49
|
workflowType: string;
|
|
50
50
|
workflowExecutionToken?: string;
|
|
51
|
+
/**
|
|
52
|
+
* The dispatching workflow run's persisted revision (WFT-20), when the
|
|
53
|
+
* `TaskDispatch` caller supplied one. Same optionality rationale as
|
|
54
|
+
* `workflowExecutionToken` above — NOT the same field as
|
|
55
|
+
* `executionRequirement.workflowRevision` (a client-declared routing
|
|
56
|
+
* constraint carried by `WorkerExecutionRequirementInput`, unrelated to
|
|
57
|
+
* this plain wire echo/validation field).
|
|
58
|
+
*/
|
|
59
|
+
workflowRevision?: string;
|
|
51
60
|
activityName: string;
|
|
52
61
|
queue: string;
|
|
53
62
|
input: JSONValue;
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*
|
|
11
11
|
* @module server/task-ledger
|
|
12
12
|
*/
|
|
13
|
-
export { decodeRemoteTaskRecord, encodeRemoteTaskRecord, isRemoteTaskCancelling, isRemoteTaskCompleting, isRemoteTaskDeadLettered, isRemoteTaskLeased, isRemoteTaskQueued, isRemoteTaskRecord, isRemoteTaskTerminal, isRemoteTaskTerminalCancelled, isRemoteTaskTerminalResolved, isRemoteTaskTerminalRetryExhausted, isValidTaskHeaders, } from './task-ledger-codec.ts';
|
|
13
|
+
export { decodeRemoteTaskRecord, encodeRemoteTaskRecord, isRemoteTaskCancelling, isRemoteTaskCompleting, isRemoteTaskDeadLettered, isRemoteTaskLeased, isRemoteTaskQueued, isRemoteTaskRecord, isRemoteTaskTerminal, isRemoteTaskTerminalCancelled, isRemoteTaskTerminalResolved, isRemoteTaskTerminalRetryExhausted, isValidOperationId, isValidTaskHeaders, isValidWorkflowRevision, } from './task-ledger-codec.ts';
|
|
14
14
|
export { taskLedgerKey } from './task-ledger-keys.ts';
|
|
15
15
|
export { MAX_TASK_HEADER_COUNT, MAX_TASK_HEADER_VALUE_BYTES, MAX_TASK_IDENTIFIER_BYTES, MAX_TASK_REASON_BYTES, utf8ByteLength, } from './task-ledger-limits.ts';
|
|
16
16
|
export { REMOTE_TASK_RECORD_VERSION } from './task-ledger-types.ts';
|
|
@@ -11,7 +11,9 @@ export {
|
|
|
11
11
|
isRemoteTaskTerminalCancelled,
|
|
12
12
|
isRemoteTaskTerminalResolved,
|
|
13
13
|
isRemoteTaskTerminalRetryExhausted,
|
|
14
|
-
|
|
14
|
+
isValidOperationId,
|
|
15
|
+
isValidTaskHeaders,
|
|
16
|
+
isValidWorkflowRevision
|
|
15
17
|
} from "./task-ledger-codec.js";
|
|
16
18
|
export { taskLedgerKey } from "./task-ledger-keys.js";
|
|
17
19
|
export {
|
|
@@ -15,6 +15,8 @@ export interface PendingTask extends TaskLifecycleFields {
|
|
|
15
15
|
workflowId?: string | undefined;
|
|
16
16
|
/** Durable token for the workflow run that dispatched this activity, when known. */
|
|
17
17
|
workflowExecutionToken?: string | undefined;
|
|
18
|
+
/** The dispatching workflow run's persisted revision (WFT-20), when known. */
|
|
19
|
+
workflowRevision?: string | undefined;
|
|
18
20
|
/**
|
|
19
21
|
* Task priority. Higher values are dequeued first. Tasks with equal priority
|
|
20
22
|
* maintain FIFO order. Default: 0. Agent workflow tasks use priority 10.
|