@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
|
@@ -60,6 +60,7 @@ export declare const getTaskDetailOperation: import("../operation-catalog.ts").O
|
|
|
60
60
|
adoptedAt?: number | undefined;
|
|
61
61
|
workflowId?: string | undefined;
|
|
62
62
|
workflowExecutionToken?: string | undefined;
|
|
63
|
+
workflowRevision?: string | undefined;
|
|
63
64
|
priority?: number | undefined;
|
|
64
65
|
retryPolicy?: {
|
|
65
66
|
maxAttempts: number;
|
|
@@ -95,6 +96,7 @@ export declare const getTaskDetailOperation: import("../operation-catalog.ts").O
|
|
|
95
96
|
adoptedAt?: number | undefined;
|
|
96
97
|
workflowId?: string | undefined;
|
|
97
98
|
workflowExecutionToken?: string | undefined;
|
|
99
|
+
workflowRevision?: string | undefined;
|
|
98
100
|
priority?: number | undefined;
|
|
99
101
|
retryPolicy?: {
|
|
100
102
|
maxAttempts: number;
|
|
@@ -130,6 +132,7 @@ export declare const getTaskDetailOperation: import("../operation-catalog.ts").O
|
|
|
130
132
|
adoptedAt?: number | undefined;
|
|
131
133
|
workflowId?: string | undefined;
|
|
132
134
|
workflowExecutionToken?: string | undefined;
|
|
135
|
+
workflowRevision?: string | undefined;
|
|
133
136
|
priority?: number | undefined;
|
|
134
137
|
retryPolicy?: {
|
|
135
138
|
maxAttempts: number;
|
|
@@ -168,6 +171,7 @@ export declare const getTaskDetailOperation: import("../operation-catalog.ts").O
|
|
|
168
171
|
lastRequeueReason?: string | undefined;
|
|
169
172
|
workflowId?: string | undefined;
|
|
170
173
|
workflowExecutionToken?: string | undefined;
|
|
174
|
+
workflowRevision?: string | undefined;
|
|
171
175
|
priority?: number | undefined;
|
|
172
176
|
retryPolicy?: {
|
|
173
177
|
maxAttempts: number;
|
|
@@ -206,6 +210,7 @@ export declare const getTaskDetailOperation: import("../operation-catalog.ts").O
|
|
|
206
210
|
lastRequeueReason?: string | undefined;
|
|
207
211
|
workflowId?: string | undefined;
|
|
208
212
|
workflowExecutionToken?: string | undefined;
|
|
213
|
+
workflowRevision?: string | undefined;
|
|
209
214
|
priority?: number | undefined;
|
|
210
215
|
retryPolicy?: {
|
|
211
216
|
maxAttempts: number;
|
|
@@ -246,6 +251,7 @@ export declare const getTaskDetailOperation: import("../operation-catalog.ts").O
|
|
|
246
251
|
lastRequeueReason?: string | undefined;
|
|
247
252
|
workflowId?: string | undefined;
|
|
248
253
|
workflowExecutionToken?: string | undefined;
|
|
254
|
+
workflowRevision?: string | undefined;
|
|
249
255
|
priority?: number | undefined;
|
|
250
256
|
retryPolicy?: {
|
|
251
257
|
maxAttempts: number;
|
|
@@ -286,6 +292,7 @@ export declare const getTaskDetailOperation: import("../operation-catalog.ts").O
|
|
|
286
292
|
lastRequeueReason?: string | undefined;
|
|
287
293
|
workflowId?: string | undefined;
|
|
288
294
|
workflowExecutionToken?: string | undefined;
|
|
295
|
+
workflowRevision?: string | undefined;
|
|
289
296
|
priority?: number | undefined;
|
|
290
297
|
retryPolicy?: {
|
|
291
298
|
maxAttempts: number;
|
|
@@ -324,6 +331,7 @@ export declare const getTaskDetailOperation: import("../operation-catalog.ts").O
|
|
|
324
331
|
lastRequeueReason?: string | undefined;
|
|
325
332
|
workflowId?: string | undefined;
|
|
326
333
|
workflowExecutionToken?: string | undefined;
|
|
334
|
+
workflowRevision?: string | undefined;
|
|
327
335
|
priority?: number | undefined;
|
|
328
336
|
retryPolicy?: {
|
|
329
337
|
maxAttempts: number;
|
|
@@ -38,6 +38,7 @@ function baseEnvelopeFields(record) {
|
|
|
38
38
|
operationId: record.operationId,
|
|
39
39
|
...record.workflowId !== void 0 ? { workflowId: record.workflowId } : {},
|
|
40
40
|
...record.workflowExecutionToken !== void 0 ? { workflowExecutionToken: record.workflowExecutionToken } : {},
|
|
41
|
+
...record.workflowRevision !== void 0 ? { workflowRevision: record.workflowRevision } : {},
|
|
41
42
|
workflowType: record.workflowType,
|
|
42
43
|
activityName: record.activityName,
|
|
43
44
|
queue: record.queue,
|
|
@@ -60,8 +60,8 @@ declare const taskDiagnosticItemSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
60
60
|
}>;
|
|
61
61
|
state: z.ZodEnum<{
|
|
62
62
|
"dead-lettered": "dead-lettered";
|
|
63
|
-
queued: "queued";
|
|
64
63
|
resolved: "resolved";
|
|
64
|
+
queued: "queued";
|
|
65
65
|
inflight: "inflight";
|
|
66
66
|
capacity: "capacity";
|
|
67
67
|
}>;
|
|
@@ -122,8 +122,8 @@ declare const getTaskDiagnosticsOutput: z.ZodObject<{
|
|
|
122
122
|
}>;
|
|
123
123
|
state: z.ZodEnum<{
|
|
124
124
|
"dead-lettered": "dead-lettered";
|
|
125
|
-
queued: "queued";
|
|
126
125
|
resolved: "resolved";
|
|
126
|
+
queued: "queued";
|
|
127
127
|
inflight: "inflight";
|
|
128
128
|
capacity: "capacity";
|
|
129
129
|
}>;
|
|
@@ -217,7 +217,7 @@ export declare function createGetTaskDiagnosticsOperation(options?: GetTaskDiagn
|
|
|
217
217
|
}, {
|
|
218
218
|
items: ({
|
|
219
219
|
kind: "dead-lettered" | "stuck-queued" | "stale-inflight" | "retry-storm" | "all-workers-at-capacity";
|
|
220
|
-
state: "dead-lettered" | "
|
|
220
|
+
state: "dead-lettered" | "resolved" | "queued" | "inflight" | "capacity";
|
|
221
221
|
retryCount: number;
|
|
222
222
|
requeueCount: number;
|
|
223
223
|
evidence: string[];
|
|
@@ -279,7 +279,7 @@ export declare const getTaskDiagnosticsOperation: import("../operation-catalog.t
|
|
|
279
279
|
}, {
|
|
280
280
|
items: ({
|
|
281
281
|
kind: "dead-lettered" | "stuck-queued" | "stale-inflight" | "retry-storm" | "all-workers-at-capacity";
|
|
282
|
-
state: "dead-lettered" | "
|
|
282
|
+
state: "dead-lettered" | "resolved" | "queued" | "inflight" | "capacity";
|
|
283
283
|
retryCount: number;
|
|
284
284
|
requeueCount: number;
|
|
285
285
|
evidence: string[];
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `weft.workflows.revisions.preload` operation + REST binding.
|
|
3
|
+
*
|
|
4
|
+
* Loads, validates, and installs one dynamic workflow source revision
|
|
5
|
+
* previously recorded via `engine.registerSource()` — a thin, documented
|
|
6
|
+
* exposure of `engine.workflows.preload()` (WFT-15/16). Modeled on
|
|
7
|
+
* `install-workflow-revision.ts` / `activate-workflow-revision.ts`.
|
|
8
|
+
*
|
|
9
|
+
* @module server/operations/preload-workflow-revision
|
|
10
|
+
*/
|
|
11
|
+
import { z } from 'zod';
|
|
12
|
+
import type { WorkflowRevisionRecord } from '../../core/catalog/index.ts';
|
|
13
|
+
import type { UnknownRestBinding } from '../rest-bindings.ts';
|
|
14
|
+
declare const preloadWorkflowRevisionInput: z.ZodObject<{
|
|
15
|
+
name: z.ZodUnknown;
|
|
16
|
+
revision: z.ZodUnknown;
|
|
17
|
+
}, z.core.$strip>;
|
|
18
|
+
export type PreloadWorkflowRevisionInput = z.infer<typeof preloadWorkflowRevisionInput>;
|
|
19
|
+
export type PreloadWorkflowRevisionOutput = WorkflowRevisionRecord;
|
|
20
|
+
export declare const preloadWorkflowRevisionOperation: import("../operation-catalog.ts").OperationDefinition<{
|
|
21
|
+
name: unknown;
|
|
22
|
+
revision: unknown;
|
|
23
|
+
}, Readonly<{
|
|
24
|
+
manifest: import("../../index.ts").WorkflowRevisionManifest;
|
|
25
|
+
installedAt: number;
|
|
26
|
+
}>, unknown>;
|
|
27
|
+
export declare const preloadWorkflowRevisionRestBinding: UnknownRestBinding;
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { isWeftError } from "../../core/weft-error.js";
|
|
3
|
+
import { defineOperation } from "../operation-registry.js";
|
|
4
|
+
import {
|
|
5
|
+
readWorkflowCatalogRestBody,
|
|
6
|
+
throwWorkflowCatalogOperationFault,
|
|
7
|
+
validateWorkflowNameField,
|
|
8
|
+
validateWorkflowRevisionField,
|
|
9
|
+
workflowsAdminAccess
|
|
10
|
+
} from "./workflow-catalog-operation-helpers.js";
|
|
11
|
+
const preloadWorkflowRevisionInput = z.object({
|
|
12
|
+
name: z.unknown().describe("Workflow name. Runtime validation requires a wire-safe identifier."),
|
|
13
|
+
revision: z.unknown().describe("The registerSource()-registered revision to load, validate, and install. Runtime validation requires a non-empty string.")
|
|
14
|
+
}), preloadWorkflowRevisionOutput = z.unknown();
|
|
15
|
+
export const preloadWorkflowRevisionOperation = defineOperation({
|
|
16
|
+
name: "weft.workflows.revisions.preload",
|
|
17
|
+
mcpExposable: !1,
|
|
18
|
+
summary: "Load, validate, and install a registered dynamic workflow source revision",
|
|
19
|
+
description: "Load, validate, and install `(name, revision)` \u2014 previously recorded via " + "engine.registerSource() \u2014 durably into the workflow catalog. Faults NotFound when no " + "source was ever registered for this exact key, and Conflict when the load fails or the loaded module fails validation.",
|
|
20
|
+
destructive: !1,
|
|
21
|
+
tags: ["Workflow Catalog"],
|
|
22
|
+
inputSchema: preloadWorkflowRevisionInput,
|
|
23
|
+
outputSchema: preloadWorkflowRevisionOutput,
|
|
24
|
+
access: workflowsAdminAccess,
|
|
25
|
+
producibleFaults: ["InvalidParams", "NotFound", "Conflict"],
|
|
26
|
+
discoverable: !0,
|
|
27
|
+
transports: { http: !0, jsonRpcHttp: !0, jsonRpcWebSocket: !0, jsonRpcStdio: !0 },
|
|
28
|
+
unknownKeyPolicy: { http: "strip", jsonRpc: "reject" },
|
|
29
|
+
invoke: async ({ input, engine }) => {
|
|
30
|
+
const e = engine, name = validateWorkflowNameField(input.name), revision = validateWorkflowRevisionField(input.revision);
|
|
31
|
+
try {
|
|
32
|
+
return await e.workflows.preload(name, revision);
|
|
33
|
+
} catch (error) {
|
|
34
|
+
if (!isWeftError(error))
|
|
35
|
+
throw {
|
|
36
|
+
code: "Conflict",
|
|
37
|
+
message: `Dynamic workflow source "${name}" revision "${revision}" failed to load.`,
|
|
38
|
+
data: { reason: "load-failed" }
|
|
39
|
+
};
|
|
40
|
+
return throwWorkflowCatalogOperationFault(error);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}), preloadWorkflowRevisionRestBinding = {
|
|
44
|
+
method: "POST",
|
|
45
|
+
path: "/v1/registry/workflows/:name/preload",
|
|
46
|
+
pathParamNames: ["name"],
|
|
47
|
+
operationName: "weft.workflows.revisions.preload",
|
|
48
|
+
inputSources: {
|
|
49
|
+
name: { kind: "path", pathParam: "name" },
|
|
50
|
+
revision: { kind: "body-field", bodyField: "revision" }
|
|
51
|
+
},
|
|
52
|
+
extractInput: async (request, pathParams, context) => {
|
|
53
|
+
const body = await readWorkflowCatalogRestBody(request, context);
|
|
54
|
+
return {
|
|
55
|
+
name: pathParams.name ?? "",
|
|
56
|
+
revision: body.revision
|
|
57
|
+
};
|
|
58
|
+
},
|
|
59
|
+
success: { kind: "json", status: 200 }
|
|
60
|
+
};
|
|
@@ -6,6 +6,7 @@ export type ScheduleMutableOptionsInput = {
|
|
|
6
6
|
overlap?: unknown;
|
|
7
7
|
backfill?: unknown;
|
|
8
8
|
jitter?: unknown;
|
|
9
|
+
revisionPolicy?: unknown;
|
|
9
10
|
};
|
|
10
11
|
/** Validate the mutable schedule options shared by create and update. */
|
|
11
12
|
export declare function validateScheduleMutableOptions(input: ScheduleMutableOptionsInput): ScheduleUpdateOptions;
|
|
@@ -1,16 +1,19 @@
|
|
|
1
|
+
import { WorkflowRevisionUnavailableError } from "../../core/engine/revision-errors.js";
|
|
1
2
|
import {
|
|
2
3
|
isValidScheduleOverlapPolicy,
|
|
4
|
+
isValidScheduleRevisionPolicy,
|
|
3
5
|
normalizeScheduleUpdateOptions
|
|
4
6
|
} from "../../core/engine/validation/schedule.js";
|
|
5
7
|
import { invalidParamsFault } from "./operation-helpers.js";
|
|
6
8
|
export { isOperationFault } from "./operation-helpers.js";
|
|
7
9
|
export function validateScheduleMutableOptions(input) {
|
|
8
|
-
const description = validateScheduleDescription(input.description), overlap = validateScheduleOverlap(input.overlap), backfill = validateScheduleBackfill(input.backfill), jitter = validateScheduleJitter(input.jitter);
|
|
10
|
+
const description = validateScheduleDescription(input.description), overlap = validateScheduleOverlap(input.overlap), backfill = validateScheduleBackfill(input.backfill), jitter = validateScheduleJitter(input.jitter), revisionPolicy = validateScheduleRevisionPolicy(input.revisionPolicy);
|
|
9
11
|
return {
|
|
10
12
|
...description !== void 0 ? { description } : {},
|
|
11
13
|
...overlap !== void 0 ? { overlap } : {},
|
|
12
14
|
...backfill !== void 0 ? { backfill } : {},
|
|
13
|
-
...jitter !== void 0 ? { jitter } : {}
|
|
15
|
+
...jitter !== void 0 ? { jitter } : {},
|
|
16
|
+
...revisionPolicy !== void 0 ? { revisionPolicy } : {}
|
|
14
17
|
};
|
|
15
18
|
}
|
|
16
19
|
function validateScheduleDescription(value) {
|
|
@@ -27,6 +30,13 @@ function validateScheduleOverlap(value) {
|
|
|
27
30
|
throw invalidParamsFault('Field "overlap" must be one of skip, queue, cancel-running, allow');
|
|
28
31
|
return value;
|
|
29
32
|
}
|
|
33
|
+
function validateScheduleRevisionPolicy(value) {
|
|
34
|
+
if (value === void 0)
|
|
35
|
+
return;
|
|
36
|
+
if (!isValidScheduleRevisionPolicy(value))
|
|
37
|
+
throw invalidParamsFault('Field "revisionPolicy" must be one of active-at-fire, pinned');
|
|
38
|
+
return value;
|
|
39
|
+
}
|
|
30
40
|
function validateScheduleBackfill(value) {
|
|
31
41
|
if (value === void 0)
|
|
32
42
|
return;
|
|
@@ -51,7 +61,25 @@ function formatJitterValidationMessage(message) {
|
|
|
51
61
|
const enginePrefix = "Invalid options.jitter: ", hasEnginePrefix = message.startsWith(enginePrefix), wireDetail = (hasEnginePrefix ? message.slice(enginePrefix.length) : message).replaceAll("options.jitter", 'Field "jitter"');
|
|
52
62
|
return hasEnginePrefix ? `Field "jitter" is invalid: ${wireDetail}` : wireDetail;
|
|
53
63
|
}
|
|
64
|
+
function mapRevisionUnavailableToFault(error) {
|
|
65
|
+
if (!(error instanceof WorkflowRevisionUnavailableError))
|
|
66
|
+
return;
|
|
67
|
+
return {
|
|
68
|
+
code: "Conflict",
|
|
69
|
+
message: error.message,
|
|
70
|
+
data: { reason: error.reason }
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function isScheduleConflictMessage(normalizedMessage) {
|
|
74
|
+
return normalizedMessage.includes("already exists") || normalizedMessage.includes("cannot be resumed");
|
|
75
|
+
}
|
|
76
|
+
function isScheduleInvalidParamsMessage(message, normalizedMessage) {
|
|
77
|
+
return message.includes("Missing required field") || normalizedMessage.includes("must be") || normalizedMessage.includes("no workflow registered") || normalizedMessage.includes("cron") || normalizedMessage.includes("interval");
|
|
78
|
+
}
|
|
54
79
|
export function mapScheduleErrorToFault(scheduleId, error) {
|
|
80
|
+
const revisionFault = mapRevisionUnavailableToFault(error);
|
|
81
|
+
if (revisionFault !== void 0)
|
|
82
|
+
return revisionFault;
|
|
55
83
|
const message = error instanceof Error ? error.message : String(error), normalizedMessage = message.toLowerCase();
|
|
56
84
|
if (normalizedMessage.includes("not found"))
|
|
57
85
|
return {
|
|
@@ -59,13 +87,13 @@ export function mapScheduleErrorToFault(scheduleId, error) {
|
|
|
59
87
|
message,
|
|
60
88
|
data: { resource: "schedule", identifier: scheduleId }
|
|
61
89
|
};
|
|
62
|
-
if (
|
|
90
|
+
if (isScheduleConflictMessage(normalizedMessage))
|
|
63
91
|
return {
|
|
64
92
|
code: "Conflict",
|
|
65
93
|
message,
|
|
66
94
|
data: { reason: message }
|
|
67
95
|
};
|
|
68
|
-
if (message
|
|
96
|
+
if (isScheduleInvalidParamsMessage(message, normalizedMessage))
|
|
69
97
|
return {
|
|
70
98
|
code: "InvalidParams",
|
|
71
99
|
message,
|
|
@@ -6,6 +6,7 @@ export type SharedScheduleRestFields = {
|
|
|
6
6
|
readonly overlap: unknown;
|
|
7
7
|
readonly backfill: unknown;
|
|
8
8
|
readonly jitter: unknown;
|
|
9
|
+
readonly revisionPolicy: unknown;
|
|
9
10
|
};
|
|
10
11
|
export declare function parseScheduleRestBodyRequestRecord(request: Request, context?: RestInputContext): Promise<Record<string, unknown>>;
|
|
11
12
|
export declare function extractSharedScheduleRestFields(record: Record<string, unknown>): SharedScheduleRestFields;
|
|
@@ -90,6 +90,10 @@ import {
|
|
|
90
90
|
} from "./list-workflow-revisions.js";
|
|
91
91
|
import { listWorkflowsOperation, listWorkflowsRestBinding } from "./list-workflows.js";
|
|
92
92
|
import { pauseScheduleOperation, pauseScheduleRestBinding } from "./pause-schedule.js";
|
|
93
|
+
import {
|
|
94
|
+
preloadWorkflowRevisionOperation,
|
|
95
|
+
preloadWorkflowRevisionRestBinding
|
|
96
|
+
} from "./preload-workflow-revision.js";
|
|
93
97
|
import { purgeWorkflowsOperation, purgeWorkflowsRestBinding } from "./purge-workflows.js";
|
|
94
98
|
import {
|
|
95
99
|
queryWorkflowOperation,
|
|
@@ -178,6 +182,7 @@ export const STATIC_REST_BINDINGS = [
|
|
|
178
182
|
getRegistryRestBinding,
|
|
179
183
|
installWorkflowRevisionRestBinding,
|
|
180
184
|
activateWorkflowRevisionRestBinding,
|
|
185
|
+
preloadWorkflowRevisionRestBinding,
|
|
181
186
|
getWorkflowRevisionRestBinding,
|
|
182
187
|
listWorkflowRevisionsRestBinding,
|
|
183
188
|
getActiveWorkflowRevisionRestBinding,
|
|
@@ -247,6 +252,7 @@ export const STATIC_REST_BINDINGS = [
|
|
|
247
252
|
getRegistryOperation,
|
|
248
253
|
installWorkflowRevisionOperation,
|
|
249
254
|
activateWorkflowRevisionOperation,
|
|
255
|
+
preloadWorkflowRevisionOperation,
|
|
250
256
|
getWorkflowRevisionOperation,
|
|
251
257
|
listWorkflowRevisionsOperation,
|
|
252
258
|
getActiveWorkflowRevisionOperation,
|
|
@@ -8,6 +8,7 @@ declare const updateScheduleInput: z.ZodObject<{
|
|
|
8
8
|
overlap: z.ZodOptional<z.ZodUnknown>;
|
|
9
9
|
backfill: z.ZodOptional<z.ZodUnknown>;
|
|
10
10
|
jitter: z.ZodOptional<z.ZodUnknown>;
|
|
11
|
+
revisionPolicy: z.ZodOptional<z.ZodUnknown>;
|
|
11
12
|
}, z.core.$strip>;
|
|
12
13
|
export type UpdateScheduleInput = z.infer<typeof updateScheduleInput>;
|
|
13
14
|
export declare const updateScheduleOperation: import("../operation-catalog.ts").OperationDefinition<{
|
|
@@ -18,6 +19,7 @@ export declare const updateScheduleOperation: import("../operation-catalog.ts").
|
|
|
18
19
|
overlap?: unknown;
|
|
19
20
|
backfill?: unknown;
|
|
20
21
|
jitter?: unknown;
|
|
22
|
+
revisionPolicy?: unknown;
|
|
21
23
|
}, null, unknown>;
|
|
22
24
|
export declare const updateScheduleRestBinding: UnknownRestBinding;
|
|
23
25
|
export {};
|
|
@@ -16,7 +16,8 @@ const updateScheduleInput = z.object({
|
|
|
16
16
|
description: z.unknown().optional().describe("Operator-facing schedule description. Runtime validation requires a string."),
|
|
17
17
|
overlap: z.unknown().optional(),
|
|
18
18
|
backfill: z.unknown().optional(),
|
|
19
|
-
jitter: z.unknown().optional()
|
|
19
|
+
jitter: z.unknown().optional(),
|
|
20
|
+
revisionPolicy: z.unknown().optional().describe('Revision policy (WFT-20). Runtime validation requires "active-at-fire" or "pinned". Omitted preserves the current policy (and pin); "pinned" always re-resolves and re-captures the pin against the revision active right now.')
|
|
20
21
|
});
|
|
21
22
|
export const updateScheduleOperation = defineOperation({
|
|
22
23
|
name: "weft.schedules.update",
|
|
@@ -52,7 +53,8 @@ export const updateScheduleOperation = defineOperation({
|
|
|
52
53
|
description: { kind: "body-field", bodyField: "description" },
|
|
53
54
|
overlap: { kind: "body-field", bodyField: "overlap" },
|
|
54
55
|
backfill: { kind: "body-field", bodyField: "backfill" },
|
|
55
|
-
jitter: { kind: "body-field", bodyField: "jitter" }
|
|
56
|
+
jitter: { kind: "body-field", bodyField: "jitter" },
|
|
57
|
+
revisionPolicy: { kind: "body-field", bodyField: "revisionPolicy" }
|
|
56
58
|
},
|
|
57
59
|
extractInput: async (request, pathParams, context) => {
|
|
58
60
|
const record = await parseScheduleRestBodyRequestRecord(request, context);
|
|
@@ -5,7 +5,12 @@ import {
|
|
|
5
5
|
} from "../../core/catalog/index.js";
|
|
6
6
|
import { MAX_CONTRACT_IDENTIFIER_BYTES } from "../../core/contract/limits.js";
|
|
7
7
|
import { parseWorkflowRevisionManifest } from "../../core/contract/manifest-parse.js";
|
|
8
|
+
import {
|
|
9
|
+
DynamicWorkflowSourceUnavailableError,
|
|
10
|
+
WorkflowSourceNotRegisteredError
|
|
11
|
+
} from "../../core/engine/dynamic-source-errors.js";
|
|
8
12
|
import { WorkflowNotRegisteredError } from "../../core/engine/errors.js";
|
|
13
|
+
import { WorkflowSourceValidationError } from "../../core/source/errors.js";
|
|
9
14
|
import { validateWorkflowOrActivityName } from "../../core/types/name-grammar.js";
|
|
10
15
|
import { readRestJsonBody } from "../rest-body.js";
|
|
11
16
|
import { invalidParamsFault, isOperationFault } from "./operation-helpers.js";
|
|
@@ -121,6 +126,28 @@ export function throwWorkflowCatalogOperationFault(error) {
|
|
|
121
126
|
message: error.message,
|
|
122
127
|
data: { reason: "catalog-conflict", weftCode: error.code }
|
|
123
128
|
};
|
|
129
|
+
if (error instanceof WorkflowSourceNotRegisteredError)
|
|
130
|
+
throw {
|
|
131
|
+
code: "NotFound",
|
|
132
|
+
message: error.message,
|
|
133
|
+
data: { resource: "workflow-source", identifier: error.workflowType, weftCode: error.code }
|
|
134
|
+
};
|
|
135
|
+
if (error instanceof DynamicWorkflowSourceUnavailableError)
|
|
136
|
+
throw {
|
|
137
|
+
code: "Conflict",
|
|
138
|
+
message: error.reason === "load-failed" ? `Dynamic workflow source "${error.workflowType}"${error.revision === void 0 ? "" : ` revision "${error.revision}"`} failed to load.` : error.message,
|
|
139
|
+
data: { reason: error.reason, weftCode: error.code }
|
|
140
|
+
};
|
|
141
|
+
if (error instanceof WorkflowSourceValidationError)
|
|
142
|
+
throw {
|
|
143
|
+
code: "Conflict",
|
|
144
|
+
message: error.message,
|
|
145
|
+
data: {
|
|
146
|
+
reason: "validation-failed",
|
|
147
|
+
sourceValidationReasons: error.reasons,
|
|
148
|
+
weftCode: error.code
|
|
149
|
+
}
|
|
150
|
+
};
|
|
124
151
|
throw error;
|
|
125
152
|
}
|
|
126
153
|
export async function readWorkflowCatalogRestBody(request, context) {
|
|
@@ -146,6 +146,17 @@ export type RestBinding<Input, Output> = {
|
|
|
146
146
|
* path param would propagate to the engine as a confusingly-shaped
|
|
147
147
|
* "missing" identifier, and surfacing the shape error at the router
|
|
148
148
|
* (404) produces a cleaner wire response than a downstream 400.
|
|
149
|
+
*
|
|
150
|
+
* WHATWG URL path normalization collapses `.` and `..` path segments (and
|
|
151
|
+
* their percent-encoded forms) before `handleRequest()` ever sees
|
|
152
|
+
* `url.pathname` — this function never observes those segments as literal
|
|
153
|
+
* text, so a single trailing `:id`/`:operationId` segment can never match a
|
|
154
|
+
* resource whose id is literally `.` or `..`, no matter how it is encoded.
|
|
155
|
+
* This is no longer just a documented gap: `assertValidWorkflowId` (WFT-95)
|
|
156
|
+
* and `isValidOperationId` reject those exact strings at admission, so a
|
|
157
|
+
* caller-facing workflow or operation id can never legitimately be `.` or
|
|
158
|
+
* `..` in the first place — this URL-normalization quirk is closed by
|
|
159
|
+
* validation rather than left as something callers must work around.
|
|
149
160
|
*/
|
|
150
161
|
export declare function bindingPathMatches(pattern: string, actualPath: string): Record<string, string> | null;
|
|
151
162
|
/**
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build the durable task-ledger envelope a fresh dispatch would create if no
|
|
3
|
+
* ledger record exists yet, and the fresh-dispatch admission checks
|
|
4
|
+
* `dispatchTaskImpl` runs before that — split out of `task-dispatch.ts`
|
|
5
|
+
* purely to stay under this repository's 500-line-per-file ceiling, matching
|
|
6
|
+
* the existing `task-dispatch-revision.ts` precedent. There is no behavioral
|
|
7
|
+
* reason to import this module directly instead of `task-dispatch.ts`, which
|
|
8
|
+
* calls `buildCreateQueuedInput` from both `selectAndReserveWorker` and
|
|
9
|
+
* `enqueueTaskForLongPoll`, and calls the admission helpers from
|
|
10
|
+
* `dispatchTaskImpl` itself.
|
|
11
|
+
*
|
|
12
|
+
* @module server/runtime/task-dispatch-envelope
|
|
13
|
+
*/
|
|
14
|
+
import type { TaskDispatch } from '../index.ts';
|
|
15
|
+
import type { CreateQueuedInput } from '../task-ledger-transitions.ts';
|
|
16
|
+
import type { ServerContext } from './context.ts';
|
|
17
|
+
/**
|
|
18
|
+
* Wait for startup task-ledger recovery (WFT-23) — covers both the public
|
|
19
|
+
* `WeftServer.dispatchTask` entry point and `scheduleDelayedDispatch`'s timer
|
|
20
|
+
* callback, which also calls `dispatchTaskImpl` directly. A rejected gate
|
|
21
|
+
* means the recovery scan itself failed; propagate that failure loudly
|
|
22
|
+
* rather than silently returning false, which callers would read as an
|
|
23
|
+
* ordinary "no worker available" outcome.
|
|
24
|
+
*/
|
|
25
|
+
export declare function awaitTaskLedgerRecoveryReady(context: ServerContext, task: TaskDispatch): Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* Reject an invalid caller-supplied operationId before it reaches a ledger
|
|
28
|
+
* write (WFT-95). `dispatchTask()` is a public same-process API taking a
|
|
29
|
+
* caller-controlled operationId; an id equal to the exact string "." or
|
|
30
|
+
* ".." can never be addressed again over REST (a single trailing
|
|
31
|
+
* `:operationId` path segment is collapsed away by WHATWG URL path
|
|
32
|
+
* normalization before the route matcher ever sees it), so fresh-dispatch
|
|
33
|
+
* admission rejects it up front instead of writing a ledger record that
|
|
34
|
+
* becomes unreachable by id. Skipped for `redispatch` — reconstructing and
|
|
35
|
+
* redispatching an already-decoded, previously persisted ledger record
|
|
36
|
+
* (`scheduleDelayedDispatch`/`taskDispatchFromLedgerRecord`) must not
|
|
37
|
+
* re-apply an admission-only check to data that was valid when written.
|
|
38
|
+
*/
|
|
39
|
+
export declare function assertFreshDispatchOperationIdAdmissible(task: TaskDispatch, redispatch: boolean): void;
|
|
40
|
+
/** The durable envelope every fresh dispatch would create if no ledger record exists yet. */
|
|
41
|
+
export declare function buildCreateQueuedInput(task: TaskDispatch, queue: string, visibilityTimeout: number): CreateQueuedInput;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { isJSONValue } from "../../core/json.js";
|
|
2
|
+
import {
|
|
3
|
+
isValidOperationId,
|
|
4
|
+
isValidWorkflowRevision,
|
|
5
|
+
REMOTE_TASK_RECORD_VERSION
|
|
6
|
+
} from "../task-ledger.js";
|
|
7
|
+
export async function awaitTaskLedgerRecoveryReady(context, task) {
|
|
8
|
+
try {
|
|
9
|
+
await context.taskLedgerRecovery.ready;
|
|
10
|
+
} catch (error) {
|
|
11
|
+
throw Error(`Cannot dispatch task "${task.operationId}" \u2014 startup task-ledger recovery failed: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export function assertFreshDispatchOperationIdAdmissible(task, redispatch) {
|
|
15
|
+
if (redispatch || isValidOperationId(task.operationId))
|
|
16
|
+
return;
|
|
17
|
+
let formattedOperationId;
|
|
18
|
+
try {
|
|
19
|
+
formattedOperationId = JSON.stringify(task.operationId) ?? String(task.operationId);
|
|
20
|
+
} catch {
|
|
21
|
+
formattedOperationId = `<${typeof task.operationId}>`;
|
|
22
|
+
}
|
|
23
|
+
throw Error(`TaskDispatch has an invalid "operationId" (${formattedOperationId}) \u2014 it must be a non-empty, bounded identifier other than "." or "..".`);
|
|
24
|
+
}
|
|
25
|
+
function buildOptionalCreateQueuedFields(task) {
|
|
26
|
+
return {
|
|
27
|
+
...task.workflowId !== void 0 ? { workflowId: task.workflowId } : {},
|
|
28
|
+
...task.workflowExecutionToken !== void 0 ? { workflowExecutionToken: task.workflowExecutionToken } : {},
|
|
29
|
+
...task.workflowRevision !== void 0 ? { workflowRevision: task.workflowRevision } : {},
|
|
30
|
+
...task.priority !== void 0 ? { priority: task.priority } : {},
|
|
31
|
+
...task.fairShareKey !== void 0 ? { fairShareKey: task.fairShareKey } : {},
|
|
32
|
+
...task.sticky && task.workflowId !== void 0 ? { stickyWorkflowId: task.workflowId } : {},
|
|
33
|
+
...task.retryPolicy !== void 0 ? { retryPolicy: task.retryPolicy } : {}
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export function buildCreateQueuedInput(task, queue, visibilityTimeout) {
|
|
37
|
+
const input = task.input === void 0 ? null : task.input;
|
|
38
|
+
if (!isJSONValue(input))
|
|
39
|
+
throw Error(`TaskDispatch for operation "${task.operationId}" has a non-JSON-serializable "input" \u2014 the durable task ledger requires JSON-safe input.`);
|
|
40
|
+
if (task.workflowRevision !== void 0 && !isValidWorkflowRevision(task.workflowRevision))
|
|
41
|
+
throw Error(`TaskDispatch for operation "${task.operationId}" has an invalid "workflowRevision" \u2014 it must be a non-empty, bounded identifier.`);
|
|
42
|
+
return {
|
|
43
|
+
recordVersion: REMOTE_TASK_RECORD_VERSION,
|
|
44
|
+
operationId: task.operationId,
|
|
45
|
+
workflowType: task.workflowType,
|
|
46
|
+
activityName: task.activityName,
|
|
47
|
+
queue,
|
|
48
|
+
input,
|
|
49
|
+
headers: task.headers ?? {},
|
|
50
|
+
visibilityTimeoutMilliseconds: visibilityTimeout,
|
|
51
|
+
createdAt: Date.now(),
|
|
52
|
+
...buildOptionalCreateQueuedFields(task)
|
|
53
|
+
};
|
|
54
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dispatch-time revision staleness gate (WFT-20) — split out of
|
|
3
|
+
* `task-dispatch.ts` purely to stay under this repository's 500-line-per-file
|
|
4
|
+
* ceiling; there is no behavioral reason to import this module directly
|
|
5
|
+
* instead of `task-dispatch.ts`, which calls it from `dispatchTaskImpl`.
|
|
6
|
+
*
|
|
7
|
+
* @module server/runtime/task-dispatch-revision
|
|
8
|
+
*/
|
|
9
|
+
import { type ConditionalBatchCondition } from '../../storage/interface.ts';
|
|
10
|
+
import type { ServeOptions, TaskDispatch } from '../index.ts';
|
|
11
|
+
/**
|
|
12
|
+
* Reject a dispatch whose caller-supplied `workflowRevision` disagrees with
|
|
13
|
+
* `task.workflowId`'s persisted `WorkflowState.revision` — a bounded,
|
|
14
|
+
* structured failure BEFORE any worker reservation or ledger write. A no-op
|
|
15
|
+
* (never reads storage) unless BOTH `workflowId` and `workflowRevision` are
|
|
16
|
+
* supplied; a no-op when no persisted `WorkflowState` exists for `workflowId`
|
|
17
|
+
* yet (nothing to compare against — the caller opted into an extra read, not
|
|
18
|
+
* an extra existence requirement).
|
|
19
|
+
*
|
|
20
|
+
* Returns the `conditionalBatch` precondition(s) (empty when this check was a
|
|
21
|
+
* no-op) that fence the CALLER's own ledger commit on the exact workflow-state
|
|
22
|
+
* bytes just read here. This check alone is only a pre-commit read: a
|
|
23
|
+
* `start-new` restart could still displace the workflow to a different
|
|
24
|
+
* revision in the gap between this read and the caller's later ledger write.
|
|
25
|
+
* The caller MUST include the returned conditions in the SAME
|
|
26
|
+
* `conditionalBatch` call that commits the ledger record, so that gap closes
|
|
27
|
+
* atomically instead of merely being read-checked up front (WFT-20).
|
|
28
|
+
*/
|
|
29
|
+
export declare function assertDispatchTargetsFreshRevision(options: ServeOptions, task: TaskDispatch): Promise<ConditionalBatchCondition[]>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { decodeWorkflowState } from "../../core/engine/validation.js";
|
|
2
|
+
import { KEYS } from "../../storage/interface.js";
|
|
3
|
+
export async function assertDispatchTargetsFreshRevision(options, task) {
|
|
4
|
+
if (task.workflowId === void 0 || task.workflowRevision === void 0)
|
|
5
|
+
return [];
|
|
6
|
+
const workflowKey = KEYS.workflow(task.workflowId), persistedBytes = await options.engine.storage.get(workflowKey);
|
|
7
|
+
if (persistedBytes === null)
|
|
8
|
+
return [];
|
|
9
|
+
const persistedRevision = decodeWorkflowState(persistedBytes).revision;
|
|
10
|
+
if (persistedRevision !== task.workflowRevision)
|
|
11
|
+
throw Error(`TaskDispatch for operation "${task.operationId}" targets workflow "${task.workflowId}" at revision "${task.workflowRevision}", but the persisted run is pinned to revision ${persistedRevision === void 0 ? "undefined (a legacy, pre-pinning record)" : `"${persistedRevision}"`} ` + "\u2014 this dispatch is stale.");
|
|
12
|
+
return [{ key: workflowKey, expectedValue: persistedBytes }];
|
|
13
|
+
}
|
|
@@ -9,6 +9,8 @@ import type { ServerContext } from './context.ts';
|
|
|
9
9
|
*/
|
|
10
10
|
export declare function scheduleDelayedDispatch(context: ServerContext, options: ServeOptions, task: TaskDispatch, delay: number): void;
|
|
11
11
|
export declare function resolveTaskPriority(_context: ServerContext, _options: ServeOptions, task: TaskDispatch): number | undefined;
|
|
12
|
-
export declare function dispatchTaskImpl(context: ServerContext, options: ServeOptions, task: TaskDispatch
|
|
12
|
+
export declare function dispatchTaskImpl(context: ServerContext, options: ServeOptions, task: TaskDispatch, { redispatch }?: {
|
|
13
|
+
redispatch?: boolean;
|
|
14
|
+
}): Promise<boolean>;
|
|
13
15
|
/** Send a cancel message to the worker handling a specific operation. */
|
|
14
16
|
export declare function cancelTask(context: ServerContext, operationId: string): boolean;
|