@lostgradient/weft 0.2.1 → 0.4.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 +123 -43
- package/dist/cli/conformance.js +7 -1
- package/dist/cli/generated/operation-client.generated.d.ts +55 -13
- package/dist/cli/generated/operation-client.generated.js +3 -0
- package/dist/cli/help-text.d.ts +1 -1
- package/dist/cli/help-text.js +1 -0
- package/dist/cli/operation-catalog-snapshot.d.ts +8 -0
- package/dist/cli/operation-catalog-snapshot.js +11 -0
- package/dist/cli/parse-schedule-arguments.js +3 -1
- package/dist/cli/schedule.js +2 -1
- package/dist/cli/types.d.ts +1 -0
- package/dist/cli-main.js +80 -79
- package/dist/client/handle-delegation.d.ts +7 -2
- package/dist/client/handle-delegation.js +9 -1
- package/dist/client/http-client-requests.d.ts +4 -1
- package/dist/client/http-client-requests.js +10 -0
- package/dist/client/http-client.d.ts +10 -4
- package/dist/client/http-client.js +18 -1
- package/dist/client/http-request.d.ts +11 -1
- package/dist/client/http-request.js +17 -7
- package/dist/client/index.d.ts +1 -1
- package/dist/client/interface.d.ts +100 -4
- package/dist/client/local.d.ts +7 -1
- package/dist/client/local.js +17 -2
- package/dist/client/start-body.d.ts +9 -2
- package/dist/client/start-body.js +13 -4
- package/dist/core/byte-arrays.d.ts +5 -0
- package/dist/core/byte-arrays.js +5 -0
- package/dist/core/checkpoint/lifecycle.d.ts +3 -0
- package/dist/core/checkpoint/lifecycle.js +9 -4
- package/dist/core/checkpoint/serialization.js +12 -5
- package/dist/core/codec/extension-codec.d.ts +16 -0
- package/dist/core/codec/extension-codec.js +104 -8
- package/dist/core/codec/index.d.ts +1 -0
- package/dist/core/codec/index.js +1 -0
- package/dist/core/codec/serializer-registry.d.ts +122 -0
- package/dist/core/codec/serializer-registry.js +51 -0
- package/dist/core/context/activity-retry-state.d.ts +38 -0
- package/dist/core/context/activity-retry-state.js +89 -0
- package/dist/core/context/activity-schedule-to-close.d.ts +159 -0
- package/dist/core/context/activity-schedule-to-close.js +69 -0
- package/dist/core/context/child-workflow-pipe.d.ts +5 -5
- package/dist/core/context/child-workflow-pipe.js +15 -2
- package/dist/core/context/context-presence.d.ts +19 -0
- package/dist/core/context/context-presence.js +13 -0
- package/dist/core/context/durable-operations.d.ts +25 -0
- package/dist/core/context/durable-operations.js +64 -0
- package/dist/core/context/index.d.ts +18 -5
- package/dist/core/context/index.js +17 -12
- package/dist/core/context/internals.d.ts +29 -0
- package/dist/core/context/internals.js +6 -1
- package/dist/core/context/operation-request.d.ts +35 -0
- package/dist/core/context/parallel-cache-entry.d.ts +14 -5
- package/dist/core/context/run-operation.d.ts +21 -3
- package/dist/core/context/run-operation.js +56 -93
- package/dist/core/context/session-state.js +7 -8
- package/dist/core/context/speculative-child.js +2 -0
- package/dist/core/context/types.d.ts +15 -0
- package/dist/core/context/version-patching.d.ts +8 -0
- package/dist/core/context/version-patching.js +40 -0
- package/dist/core/context/workflow-logger.d.ts +98 -0
- package/dist/core/context/workflow-logger.js +68 -0
- package/dist/core/engine/activity-heartbeat-tracking.d.ts +64 -0
- package/dist/core/engine/activity-heartbeat-tracking.js +42 -0
- package/dist/core/engine/activity-per-attempt-timeout.d.ts +41 -0
- package/dist/core/engine/activity-per-attempt-timeout.js +36 -0
- package/dist/core/engine/activity-reconciliation.d.ts +1 -0
- package/dist/core/engine/activity-reconciliation.js +12 -1
- package/dist/core/engine/activity-resolution.d.ts +23 -0
- package/dist/core/engine/activity-resolution.js +37 -0
- package/dist/core/engine/aggregate.js +66 -30
- package/dist/core/engine/async-activity-completion.d.ts +23 -6
- package/dist/core/engine/async-activity-completion.js +53 -12
- package/dist/core/engine/attributes-tags.js +9 -4
- package/dist/core/engine/bulk-operations-purge.d.ts +26 -0
- package/dist/core/engine/bulk-operations-purge.js +38 -3
- package/dist/core/engine/bulk-operations-shared.d.ts +2 -0
- package/dist/core/engine/bulk-operations-shared.js +8 -2
- package/dist/core/engine/bulk-operations.d.ts +4 -1
- package/dist/core/engine/bulk-operations.js +235 -24
- package/dist/core/engine/callback-creators-bundles.d.ts +9 -0
- package/dist/core/engine/callback-creators-bundles.js +30 -2
- package/dist/core/engine/callback-creators-core.js +6 -4
- package/dist/core/engine/callback-creators-router.js +10 -0
- package/dist/core/engine/callback-creators-schedule.d.ts +2 -2
- package/dist/core/engine/callback-creators-schedule.js +12 -8
- package/dist/core/engine/candidate-read-batching.d.ts +6 -0
- package/dist/core/engine/candidate-read-batching.js +1 -0
- package/dist/core/engine/checkpoint-io.js +61 -25
- package/dist/core/engine/checkpoint-reads.js +3 -2
- package/dist/core/engine/checkpoint-replay.d.ts +20 -0
- package/dist/core/engine/checkpoint-replay.js +242 -0
- package/dist/core/engine/checkpoint-side-effects.d.ts +23 -0
- package/dist/core/engine/checkpoint-side-effects.js +35 -0
- package/dist/core/engine/child-workflow-cancellation.d.ts +10 -0
- package/dist/core/engine/child-workflow-cancellation.js +40 -0
- package/dist/core/engine/child-workflow.js +27 -4
- package/dist/core/engine/condition-waiters.d.ts +14 -0
- package/dist/core/engine/condition-waiters.js +5 -0
- package/dist/core/engine/construction.d.ts +3 -1
- package/dist/core/engine/construction.js +30 -8
- package/dist/core/engine/coordination-branch-executors.d.ts +70 -0
- package/dist/core/engine/coordination-branch-executors.js +107 -0
- package/dist/core/engine/deferred-consume-envelope.d.ts +59 -0
- package/dist/core/engine/deferred-consume-envelope.js +14 -0
- package/dist/core/engine/disposal.js +25 -0
- package/dist/core/engine/engine-create-types.d.ts +14 -18
- package/dist/core/engine/engine-internal-types.d.ts +38 -3
- package/dist/core/engine/engine-leak-warnings.d.ts +6 -0
- package/dist/core/engine/engine-leak-warnings.js +4 -0
- package/dist/core/engine/engine-runtime-helpers.d.ts +17 -0
- package/dist/core/engine/engine-runtime-helpers.js +26 -5
- package/dist/core/engine/errors.d.ts +121 -0
- package/dist/core/engine/errors.js +45 -1
- package/dist/core/engine/event-log-compaction.d.ts +8 -0
- package/dist/core/engine/event-log-compaction.js +20 -2
- package/dist/core/engine/fenced-write.d.ts +65 -0
- package/dist/core/engine/fenced-write.js +71 -0
- package/dist/core/engine/finalizer-state.d.ts +28 -0
- package/dist/core/engine/finalizer-state.js +16 -0
- package/dist/core/engine/handle-result.js +1 -1
- package/dist/core/engine/handles.d.ts +97 -40
- package/dist/core/engine/handles.js +25 -27
- package/dist/core/engine/index.d.ts +125 -15
- package/dist/core/engine/index.js +207 -11
- package/dist/core/engine/inline-launch-queue.d.ts +14 -0
- package/dist/core/engine/inline-launch-queue.js +32 -7
- package/dist/core/engine/inline-parking.js +3 -2
- package/dist/core/engine/internals.d.ts +125 -13
- package/dist/core/engine/lease-codec.d.ts +35 -0
- package/dist/core/engine/lease-codec.js +32 -0
- package/dist/core/engine/lease-deposition.d.ts +66 -0
- package/dist/core/engine/lease-deposition.js +10 -0
- package/dist/core/engine/lease-errors.d.ts +99 -0
- package/dist/core/engine/lease-errors.js +30 -0
- package/dist/core/engine/lease-manager.d.ts +114 -0
- package/dist/core/engine/lease-manager.js +135 -0
- package/dist/core/engine/lifecycle/fork-helpers.js +1 -7
- package/dist/core/engine/lifecycle/persist.js +15 -52
- package/dist/core/engine/lifecycle/recovered-services.d.ts +8 -6
- package/dist/core/engine/lifecycle/recovered-services.js +18 -3
- package/dist/core/engine/lifecycle/resume.js +39 -11
- package/dist/core/engine/lifecycle/shared.d.ts +8 -1
- package/dist/core/engine/lifecycle/start-batch.d.ts +1 -1
- package/dist/core/engine/lifecycle/start-batch.js +2 -1
- package/dist/core/engine/lifecycle/start-commit.d.ts +56 -0
- package/dist/core/engine/lifecycle/start-commit.js +69 -0
- package/dist/core/engine/lifecycle/start-exec.d.ts +30 -2
- package/dist/core/engine/lifecycle/start-exec.js +38 -0
- package/dist/core/engine/lifecycle/start-or-signal-create.d.ts +58 -0
- package/dist/core/engine/lifecycle/start-or-signal-create.js +95 -0
- package/dist/core/engine/lifecycle/start-or-signal-resolution.d.ts +79 -0
- package/dist/core/engine/lifecycle/start-or-signal-resolution.js +60 -0
- package/dist/core/engine/lifecycle/start-or-signal.d.ts +46 -0
- package/dist/core/engine/lifecycle/start-or-signal.js +71 -0
- package/dist/core/engine/lifecycle/start-terminal-conflict-purge.d.ts +39 -0
- package/dist/core/engine/lifecycle/start-terminal-conflict-purge.js +28 -0
- package/dist/core/engine/lifecycle/start.d.ts +6 -6
- package/dist/core/engine/lifecycle/start.js +47 -45
- package/dist/core/engine/lifecycle/transition.js +17 -5
- package/dist/core/engine/lifecycle.d.ts +3 -2
- package/dist/core/engine/lifecycle.js +9 -2
- package/dist/core/engine/list-candidate-resolution.js +2 -2
- package/dist/core/engine/listing.js +10 -6
- package/dist/core/engine/operations-activity.d.ts +4 -11
- package/dist/core/engine/operations-activity.js +22 -49
- package/dist/core/engine/operations-coordination.d.ts +10 -0
- package/dist/core/engine/operations-coordination.js +43 -8
- package/dist/core/engine/operations-router.d.ts +6 -0
- package/dist/core/engine/operations-router.js +2 -0
- package/dist/core/engine/operations-speculate.js +6 -2
- package/dist/core/engine/operations-stream.js +12 -2
- package/dist/core/engine/operations-time.d.ts +4 -2
- package/dist/core/engine/operations-time.js +14 -2
- package/dist/core/engine/operations-wait-condition.d.ts +23 -0
- package/dist/core/engine/operations-wait-condition.js +62 -0
- package/dist/core/engine/ownership-options.d.ts +23 -0
- package/dist/core/engine/ownership-options.js +26 -0
- package/dist/core/engine/payload-size-policy.d.ts +3 -0
- package/dist/core/engine/payload-size-policy.js +4 -0
- package/dist/core/engine/pending-updates.d.ts +17 -0
- package/dist/core/engine/pending-updates.js +33 -11
- package/dist/core/engine/persisted-data-version.d.ts +5 -9
- package/dist/core/engine/persisted-data-version.js +4 -5
- package/dist/core/engine/queries.js +1 -1
- package/dist/core/engine/registration.d.ts +1 -0
- package/dist/core/engine/registration.js +18 -3
- package/dist/core/engine/schedule-handle.d.ts +45 -0
- package/dist/core/engine/schedule-handle.js +26 -0
- package/dist/core/engine/schedule-jitter.d.ts +5 -0
- package/dist/core/engine/schedule-jitter.js +10 -0
- package/dist/core/engine/schedule-run.d.ts +17 -0
- package/dist/core/engine/schedule-run.js +38 -0
- package/dist/core/engine/schedule-timer.js +81 -17
- package/dist/core/engine/schedules.d.ts +8 -5
- package/dist/core/engine/schedules.js +44 -19
- package/dist/core/engine/search-attribute-records.d.ts +4 -0
- package/dist/core/engine/search-attribute-records.js +17 -0
- package/dist/core/engine/second-instance-detector.d.ts +96 -0
- package/dist/core/engine/second-instance-detector.js +108 -0
- package/dist/core/engine/signals.d.ts +38 -0
- package/dist/core/engine/signals.js +55 -19
- package/dist/core/engine/state-utilities.d.ts +49 -2
- package/dist/core/engine/state-utilities.js +114 -3
- package/dist/core/engine/storage-io.d.ts +16 -2
- package/dist/core/engine/storage-io.js +26 -5
- package/dist/core/engine/stream-chunk-loading.d.ts +2 -0
- package/dist/core/engine/stream-chunk-loading.js +24 -1
- package/dist/core/engine/sub-operation.js +22 -3
- package/dist/core/engine/termination/cleanup.d.ts +28 -1
- package/dist/core/engine/termination/cleanup.js +44 -2
- package/dist/core/engine/termination/complete.js +48 -9
- package/dist/core/engine/termination/finalizer-activity.d.ts +53 -0
- package/dist/core/engine/termination/finalizer-activity.js +30 -0
- package/dist/core/engine/termination/finalizer-claim.d.ts +110 -0
- package/dist/core/engine/termination/finalizer-claim.js +80 -0
- package/dist/core/engine/termination/finalizer.d.ts +48 -0
- package/dist/core/engine/termination/finalizer.js +159 -0
- package/dist/core/engine/termination/suspend.d.ts +70 -0
- package/dist/core/engine/termination/suspend.js +41 -0
- package/dist/core/engine/termination.d.ts +5 -2
- package/dist/core/engine/termination.js +6 -0
- package/dist/core/engine/updates.js +5 -25
- package/dist/core/engine/validation/schedule.d.ts +2 -1
- package/dist/core/engine/validation/schedule.js +51 -2
- package/dist/core/engine/validation.js +54 -3
- package/dist/core/engine/waiting-update-response.d.ts +8 -0
- package/dist/core/engine/waiting-update-response.js +22 -0
- package/dist/core/engine/workflow-concurrency.d.ts +10 -0
- package/dist/core/engine/workflow-concurrency.js +136 -0
- package/dist/core/engine/workflow-feed.d.ts +9 -8
- package/dist/core/engine/workflow-feed.js +4 -1
- package/dist/core/engine/workflow-indexes.d.ts +9 -0
- package/dist/core/engine/workflow-indexes.js +10 -0
- package/dist/core/engine/workflow-state-stream.js +33 -13
- package/dist/core/engine/workflow-visibility-queries.d.ts +2 -2
- package/dist/core/engine-helpers.js +1 -0
- package/dist/core/events/activity-events.d.ts +43 -12
- package/dist/core/events/activity-events.js +28 -0
- package/dist/core/events/attribute-events.d.ts +2 -3
- package/dist/core/events/event-map.d.ts +19 -12
- package/dist/core/events/index.d.ts +1 -0
- package/dist/core/events/index.js +1 -0
- package/dist/core/events/schedule-events.d.ts +71 -0
- package/dist/core/events/schedule-events.js +29 -0
- package/dist/core/events/signal-events.d.ts +4 -6
- package/dist/core/events/system-events.d.ts +29 -19
- package/dist/core/events/system-events.js +26 -0
- package/dist/core/events/update-events.d.ts +6 -8
- package/dist/core/events/workflow-events.d.ts +108 -20
- package/dist/core/events/workflow-events.js +35 -0
- package/dist/core/failure-categories.js +5 -17
- package/dist/core/fault-code.d.ts +9 -3
- package/dist/core/fault-code.js +1 -0
- package/dist/core/inline-execution-strategy.context-options.d.ts +69 -0
- package/dist/core/inline-execution-strategy.context-options.js +56 -0
- package/dist/core/inline-execution-strategy.d.ts +31 -36
- package/dist/core/inline-execution-strategy.js +16 -27
- package/dist/core/list-filter-validation.d.ts +1 -1
- package/dist/core/list-filter-validation.js +2 -1
- package/dist/core/payload-size.d.ts +1 -1
- package/dist/core/persisted-data-incompatible-error.d.ts +9 -7
- package/dist/core/review/events.d.ts +6 -8
- package/dist/core/scheduler/scheduler-class.d.ts +10 -1
- package/dist/core/scheduler/scheduler-class.js +38 -11
- package/dist/core/scheduler/timer-batch.js +9 -1
- package/dist/core/scheduler/timer-sources.d.ts +1 -0
- package/dist/core/scheduler/timer-sources.js +11 -5
- package/dist/core/session-state.d.ts +0 -1
- package/dist/core/session-state.js +2 -2
- package/dist/core/start-workflow-validation.d.ts +56 -0
- package/dist/core/start-workflow-validation.js +30 -1
- package/dist/core/step-context.d.ts +10 -6
- package/dist/core/step-context.js +7 -15
- package/dist/core/types/activity-verification.d.ts +67 -0
- package/dist/core/types/activity-verification.js +0 -0
- package/dist/core/types/activity.d.ts +86 -64
- package/dist/core/types/bulk.d.ts +50 -9
- package/dist/core/types/checkpoint.d.ts +44 -8
- package/dist/core/types/identity.d.ts +8 -1
- package/dist/core/types/launch-metadata.d.ts +33 -0
- package/dist/core/types/launch-metadata.js +0 -0
- package/dist/core/types/list-options.d.ts +146 -0
- package/dist/core/types/list-options.js +0 -0
- package/dist/core/types/message-handles.d.ts +25 -0
- package/dist/core/types/options.d.ts +165 -215
- package/dist/core/types/reviews.d.ts +2 -1
- package/dist/core/types/schedules.d.ts +39 -3
- package/dist/core/types/services-resolution.d.ts +47 -0
- package/dist/core/types/services-resolution.js +0 -0
- package/dist/core/types/state.d.ts +11 -11
- package/dist/core/types/workflow-builder-runtime.d.ts +12 -3
- package/dist/core/types/workflow-builder-runtime.js +11 -2
- package/dist/core/types/workflow-builder.d.ts +47 -15
- package/dist/core/types/workflow-concurrency.d.ts +39 -0
- package/dist/core/types/workflow-concurrency.js +0 -0
- package/dist/core/types/workflow-context.d.ts +157 -14
- package/dist/core/types/workflow-definition.d.ts +53 -10
- package/dist/core/types/workflow-function.d.ts +101 -9
- package/dist/core/types/workflow-log.d.ts +98 -0
- package/dist/core/types/workflow-log.js +0 -0
- package/dist/core/types/workflow-registries.d.ts +14 -3
- package/dist/core/types/workflow-registry.d.ts +3 -0
- package/dist/core/types/workflow-snapshot.d.ts +29 -0
- package/dist/core/types/workflow-snapshot.js +0 -0
- package/dist/core/types.d.ts +7 -0
- package/dist/core/types.js +7 -0
- package/dist/core/versioning.d.ts +9 -39
- package/dist/core/versioning.js +2 -12
- package/dist/core/weft-error.d.ts +44 -1
- package/dist/core/weft-error.js +19 -1
- package/dist/core/worker-execution-strategy-options.d.ts +26 -0
- package/dist/core/worker-execution-strategy.js +40 -36
- package/dist/core/worker-inbound-message.d.ts +38 -0
- package/dist/core/worker-inbound-message.js +37 -0
- package/dist/core/worker-log-abuse-counter.d.ts +175 -0
- package/dist/core/worker-log-abuse-counter.js +107 -0
- package/dist/core/worker-message-helpers.d.ts +47 -0
- package/dist/core/worker-message-helpers.js +26 -0
- package/dist/core/worker-protocol-guard.js +1 -1
- package/dist/core/worker-protocol-log.d.ts +56 -0
- package/dist/core/worker-protocol-log.js +18 -0
- package/dist/core/worker-protocol.d.ts +23 -0
- package/dist/core/worker-protocol.js +12 -2
- package/dist/core/workflow-version-tuple.d.ts +3 -9
- package/dist/core/workflow-version-tuple.js +2 -3
- package/dist/diagnostics/doctor.js +6 -3
- package/dist/diagnostics/format.js +3 -8
- package/dist/diagnostics/types.d.ts +5 -5
- package/dist/diagnostics/validate.d.ts +0 -1
- package/dist/diagnostics/version-check.d.ts +1 -1
- package/dist/diagnostics/version-check.js +10 -13
- package/dist/index.d.ts +13 -11
- package/dist/index.js +39 -4
- package/dist/json-schema.js +3 -3
- package/dist/mcp/cli.js +35 -35
- package/dist/mcp/dispatcher.js +1 -1
- package/dist/mcp/http.js +16 -6
- package/dist/mcp/list-filter.js +2 -1
- package/dist/mcp/protocol.d.ts +2 -0
- package/dist/mcp/protocol.js +1 -1
- package/dist/mcp/session.d.ts +16 -0
- package/dist/mcp/session.js +60 -6
- package/dist/mcp/tools.js +73 -6
- package/dist/observability/index.js +2 -2
- package/dist/server/asyncapi-channels.js +5 -2
- package/dist/server/attribute-filters.d.ts +8 -3
- package/dist/server/attribute-filters.js +6 -1
- package/dist/server/authentication/api-key.d.ts +2 -1
- package/dist/server/authentication/api-key.js +5 -2
- package/dist/server/authentication/constant-time-api-key.d.ts +15 -0
- package/dist/server/authentication/constant-time-api-key.js +24 -0
- package/dist/server/authentication/index.d.ts +1 -1
- package/dist/server/authentication/index.js +7 -4
- package/dist/server/authentication/rotating-api-key-store.d.ts +5 -3
- package/dist/server/authentication/rotating-api-key-store.js +19 -11
- package/dist/server/engine-event-feed-backend.d.ts +4 -5
- package/dist/server/fault-to-http.js +8 -1
- package/dist/server/fault-to-json-rpc.js +1 -0
- package/dist/server/fleet-event-feed.d.ts +31 -0
- package/dist/server/fleet-event-feed.js +157 -0
- package/dist/server/handler/index.js +1 -1
- package/dist/server/handler/response-helpers.js +2 -1
- package/dist/server/handler/route-dispatch.d.ts +6 -3
- package/dist/server/handler/route-dispatch.js +2 -2
- package/dist/server/handler.js +31 -31
- package/dist/server/index.d.ts +32 -2
- package/dist/server/index.js +35 -35
- package/dist/server/interactive-operations.js +1 -0
- package/dist/server/json-rpc-transport-helpers.d.ts +1 -0
- package/dist/server/json-rpc-transport-helpers.js +2 -1
- package/dist/server/json-rpc-websocket-runtime.d.ts +11 -2
- package/dist/server/json-rpc-websocket-runtime.js +1 -0
- package/dist/server/json-rpc-websocket-subscriptions.d.ts +10 -0
- package/dist/server/json-rpc-websocket-subscriptions.js +29 -0
- package/dist/server/json-rpc-websocket-types.d.ts +22 -0
- package/dist/server/json-rpc-websocket-types.js +0 -0
- package/dist/server/json-rpc-websocket-validation.js +20 -4
- package/dist/server/json-rpc-websocket.d.ts +2 -43
- package/dist/server/json-rpc-websocket.js +57 -74
- package/dist/server/openapi.d.ts +2 -1
- package/dist/server/openapi.js +1 -3
- package/dist/server/openrpc-document-schema.d.ts +78 -0
- package/dist/server/openrpc-document-schema.js +27 -1
- package/dist/server/openrpc-errors.d.ts +3 -0
- package/dist/server/openrpc-errors.js +2 -1
- package/dist/server/openrpc.js +32 -0
- package/dist/server/operation-catalog/index.d.ts +1 -1
- package/dist/server/operation-catalog/pipeline-helpers.js +1 -0
- package/dist/server/operation-catalog/pipeline-stages.js +26 -12
- package/dist/server/operation-catalog/pipeline.js +8 -1
- package/dist/server/operation-catalog/registry.js +13 -0
- package/dist/server/operation-catalog/types.d.ts +20 -9
- package/dist/server/operation-fault.d.ts +10 -0
- package/dist/server/operation-fault.js +2 -0
- package/dist/server/operation-registry.d.ts +12 -11
- package/dist/server/operation-registry.js +12 -3
- package/dist/server/operations/aggregate-workflows.d.ts +15 -15
- package/dist/server/operations/async-activity.d.ts +2 -2
- package/dist/server/operations/async-activity.js +12 -7
- package/dist/server/operations/bulk-cancel-workflows.d.ts +1 -1
- package/dist/server/operations/bulk-cancel-workflows.js +2 -2
- package/dist/server/operations/bulk-delete-workflows.d.ts +1 -1
- package/dist/server/operations/bulk-delete-workflows.js +2 -2
- package/dist/server/operations/bulk-filter-helpers.d.ts +8 -6
- package/dist/server/operations/bulk-filter-helpers.js +54 -24
- package/dist/server/operations/bulk-mutate-workflow-tags.d.ts +11 -9
- package/dist/server/operations/bulk-mutate-workflow-tags.js +2 -2
- package/dist/server/operations/bulk-operation-helpers.d.ts +2 -2
- package/dist/server/operations/bulk-retry-failed-workflows.d.ts +7 -0
- package/dist/server/operations/bulk-retry-failed-workflows.js +64 -0
- package/dist/server/operations/bulk-signal-workflows.d.ts +11 -9
- package/dist/server/operations/bulk-signal-workflows.js +2 -2
- package/dist/server/operations/cancel-schedule.d.ts +1 -1
- package/dist/server/operations/create-schedule.d.ts +3 -1
- package/dist/server/operations/create-schedule.js +29 -11
- package/dist/server/operations/fleet-events-subscription.d.ts +54 -0
- package/dist/server/operations/fleet-events-subscription.js +99 -0
- package/dist/server/operations/fork-workflow.d.ts +1 -1
- package/dist/server/operations/fork-workflow.js +3 -2
- package/dist/server/operations/get-checkpoint-at.d.ts +1 -1
- package/dist/server/operations/get-registry.d.ts +1 -1
- package/dist/server/operations/get-retention-overview.d.ts +1 -1
- package/dist/server/operations/get-review.d.ts +1 -1
- package/dist/server/operations/get-schedule.d.ts +1 -1
- package/dist/server/operations/get-stream-chunks.d.ts +1 -1
- package/dist/server/operations/get-system-metrics.d.ts +2 -2
- package/dist/server/operations/get-task-diagnostics.d.ts +45 -6
- package/dist/server/operations/get-task-diagnostics.js +101 -7
- package/dist/server/operations/get-update-result.d.ts +1 -1
- package/dist/server/operations/get-workflow-attributes.d.ts +1 -1
- package/dist/server/operations/get-workflow-events.d.ts +1 -1
- package/dist/server/operations/get-workflow-result.d.ts +1 -1
- package/dist/server/operations/get-workflow-timeline.d.ts +1 -1
- package/dist/server/operations/get-workflow.d.ts +1 -1
- package/dist/server/operations/list-checkpoints.d.ts +1 -1
- package/dist/server/operations/list-reviews.d.ts +1 -1
- package/dist/server/operations/list-schedules.d.ts +1 -1
- package/dist/server/operations/list-task-queues.d.ts +2 -2
- package/dist/server/operations/list-workers.d.ts +2 -2
- package/dist/server/operations/list-workflows.d.ts +1 -1
- package/dist/server/operations/operation-helpers.d.ts +16 -1
- package/dist/server/operations/operation-helpers.js +15 -3
- package/dist/server/operations/pause-schedule.d.ts +1 -1
- package/dist/server/operations/purge-workflows.d.ts +5 -5
- package/dist/server/operations/purge-workflows.js +2 -2
- package/dist/server/operations/query-workflow.d.ts +1 -1
- package/dist/server/operations/query-workflow.js +3 -2
- package/dist/server/operations/recover-all.d.ts +1 -1
- package/dist/server/operations/replay-workflow.d.ts +1 -1
- package/dist/server/operations/resume-schedule.d.ts +1 -1
- package/dist/server/operations/resume-workflow.js +2 -2
- package/dist/server/operations/set-workflow-attributes.d.ts +1 -1
- package/dist/server/operations/set-workflow-attributes.js +6 -3
- package/dist/server/operations/signal-workflow.js +8 -3
- package/dist/server/operations/single-workflow-tag-mutation.js +13 -3
- package/dist/server/operations/start-or-signal-workflow.d.ts +44 -0
- package/dist/server/operations/start-or-signal-workflow.js +130 -0
- package/dist/server/operations/start-workflow-options.d.ts +38 -0
- package/dist/server/operations/start-workflow-options.js +63 -0
- package/dist/server/operations/start-workflow-rest-input.d.ts +14 -0
- package/dist/server/operations/start-workflow-rest-input.js +31 -0
- package/dist/server/operations/start-workflow.d.ts +1 -1
- package/dist/server/operations/start-workflow.js +15 -92
- package/dist/server/operations/storage.d.ts +6 -6
- package/dist/server/operations/storage.js +24 -14
- package/dist/server/operations/stream-workflow-sse.d.ts +1 -1
- package/dist/server/operations/submit-review-decision.d.ts +1 -1
- package/dist/server/operations/submit-review-decision.js +6 -3
- package/dist/server/operations/suspend-workflow.d.ts +13 -0
- package/dist/server/operations/suspend-workflow.js +36 -0
- package/dist/server/operations/update-schedule.d.ts +1 -1
- package/dist/server/operations/update-schedule.js +7 -4
- package/dist/server/operations/update-workflow.d.ts +1 -1
- package/dist/server/operations/update-workflow.js +7 -3
- package/dist/server/operations/worker-drain.d.ts +8 -8
- package/dist/server/operations/worker-drain.js +11 -8
- package/dist/server/operations/workflow-events-subscription.d.ts +7 -8
- package/dist/server/operations/workflow-events-subscription.js +43 -8
- package/dist/server/rest-binding.d.ts +21 -8
- package/dist/server/rest-bindings.js +24 -0
- package/dist/server/rest-body.d.ts +10 -0
- package/dist/server/rest-body.js +80 -0
- package/dist/server/runtime/authentication-bridge.d.ts +1 -0
- package/dist/server/runtime/authentication-bridge.js +33 -6
- package/dist/server/runtime/client-visible-events.d.ts +3 -0
- package/dist/server/runtime/client-visible-events.js +65 -0
- package/dist/server/runtime/context.d.ts +7 -0
- package/dist/server/runtime/event-broadcasting.d.ts +6 -0
- package/dist/server/runtime/event-broadcasting.js +72 -38
- package/dist/server/runtime/retry.d.ts +1 -0
- package/dist/server/runtime/retry.js +14 -0
- package/dist/server/runtime/shutdown.d.ts +7 -6
- package/dist/server/runtime/shutdown.js +6 -1
- package/dist/server/runtime/task-dispatch.js +5 -3
- package/dist/server/runtime/task-polling.d.ts +16 -2
- package/dist/server/runtime/task-polling.js +80 -24
- package/dist/server/runtime/task-reconciliation.js +9 -1
- package/dist/server/runtime/task-result-resolution.d.ts +15 -0
- package/dist/server/runtime/task-result-resolution.js +81 -0
- package/dist/server/runtime/websocket-stream.d.ts +20 -1
- package/dist/server/runtime/websocket-stream.js +173 -7
- package/dist/server/runtime/websocket-upgrade.js +22 -3
- package/dist/server/runtime/websocket-worker.d.ts +1 -1
- package/dist/server/runtime/websocket-worker.js +46 -30
- package/dist/server/serve-internals.d.ts +11 -1
- package/dist/server/serve-internals.js +20 -2
- package/dist/server/task-state.d.ts +38 -0
- package/dist/server/task-state.js +28 -0
- package/dist/server/workflow-event-feed.d.ts +36 -115
- package/dist/server/workflow-event-feed.js +92 -27
- package/dist/service-worker/index.js +31 -31
- package/dist/storage/auto.js +1 -1
- package/dist/storage/bun-sql.js +24 -0
- package/dist/storage/capabilities.d.ts +10 -2
- package/dist/storage/capabilities.js +2 -2
- package/dist/storage/compressed-storage.js +1 -1
- package/dist/storage/default-scope.d.ts +7 -4
- package/dist/storage/http.js +2 -2
- package/dist/storage/index.d.ts +81 -4
- package/dist/storage/indexeddb.js +1 -1
- package/dist/storage/interface.d.ts +189 -0
- package/dist/storage/interface.js +1 -1
- package/dist/storage/key-prefixes.d.ts +1 -1
- package/dist/storage/key-prefixes.js +12 -0
- package/dist/storage/lmdb.d.ts +4 -3
- package/dist/storage/lmdb.js +1 -1
- package/dist/storage/memory.js +1 -1
- package/dist/storage/neon-batch.d.ts +30 -0
- package/dist/storage/neon-batch.js +30 -0
- package/dist/storage/neon-value-mapping.d.ts +74 -0
- package/dist/storage/neon-value-mapping.js +23 -0
- package/dist/storage/neon.d.ts +124 -0
- package/dist/storage/neon.js +15 -0
- package/dist/storage/node-sqlite-loader.d.ts +71 -0
- package/dist/storage/node-sqlite-loader.js +41 -0
- package/dist/storage/node-sqlite.d.ts +1 -19
- package/dist/storage/node-sqlite.js +61 -32
- package/dist/storage/postgres-key-value-queries.d.ts +104 -0
- package/dist/storage/postgres-key-value-queries.js +101 -0
- package/dist/storage/resolve.d.ts +2 -165
- package/dist/storage/resolve.js +1 -1
- package/dist/storage/scoped-storage.js +1 -1
- package/dist/storage/storage-configuration.d.ts +209 -0
- package/dist/storage/storage-configuration.js +0 -0
- package/dist/storage/testing.d.ts +168 -0
- package/dist/storage/testing.js +2 -0
- package/dist/storage/text-value-store.d.ts +9 -9
- package/dist/storage/turso.d.ts +8 -0
- package/dist/storage/turso.js +2 -2
- package/dist/storage/typed-storage.js +1 -1
- package/dist/storage/web-extension.js +1 -1
- package/dist/testing/index.js +35 -35
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/worker/index.js +9 -5
- package/dist/worker/long-poll.js +4 -0
- package/dist/worker/protocol-messages.d.ts +20 -0
- package/dist/worker/protocol-schemas.d.ts +32 -0
- package/dist/worker/protocol-schemas.js +8 -4
- package/dist/worker/protocol-task-result.d.ts +28 -0
- package/dist/worker/protocol-task-result.js +76 -0
- package/dist/worker/protocol.d.ts +4 -15
- package/dist/worker/protocol.js +1 -1
- package/dist/worker/registry/fair-share.d.ts +29 -0
- package/dist/worker/registry/fair-share.js +30 -0
- package/dist/worker/registry/routing.d.ts +18 -0
- package/dist/worker/registry/routing.js +14 -0
- package/dist/worker/registry/types.d.ts +7 -0
- package/dist/worker/registry.d.ts +16 -1
- package/dist/worker/registry.js +24 -36
- package/dist/workers/worker-replay-state.d.ts +32 -0
- package/dist/workers/worker-replay-state.js +35 -0
- package/dist/workers/worker-state-namespace.d.ts +21 -0
- package/dist/workers/worker-state-namespace.js +13 -0
- package/dist/workers/workflow-runner.d.ts +19 -15
- package/dist/workers/workflow-runner.js +72 -60
- package/dist/workers/workflow-worker-entry.js +5 -2
- package/package.json +21 -4
|
@@ -1,14 +1,19 @@
|
|
|
1
|
-
import { KEYS, encodeStorageKeyComponent } from "../../../storage/interface.js";
|
|
1
|
+
import { KEYS, encodeStorageKeyComponent, storageHas } from "../../../storage/interface.js";
|
|
2
2
|
import { CleanupWarningEvent } from "../../events.js";
|
|
3
3
|
import { asyncActivityWorkflowPrefix } from "../async-activity-completion.js";
|
|
4
4
|
import { forgetCommittedCheckpointBytes } from "../checkpoint-commit-snapshots.js";
|
|
5
5
|
import { parseTerminalCleanupTimerId, workflowFeedListenerKey } from "../state-utilities.js";
|
|
6
|
+
import { releaseWorkflowConcurrencySlot } from "../workflow-concurrency.js";
|
|
6
7
|
export const TERMINAL_WORKFLOW_STATUSES = new Set([
|
|
7
8
|
"completed",
|
|
8
9
|
"failed",
|
|
9
10
|
"cancelled",
|
|
10
11
|
"timed-out"
|
|
11
|
-
])
|
|
12
|
+
]), FORCIBLY_TERMINABLE_STATUSES = [
|
|
13
|
+
"running",
|
|
14
|
+
"pending",
|
|
15
|
+
"suspended"
|
|
16
|
+
];
|
|
12
17
|
function selectTrackedWaiterMaps(internals, kind) {
|
|
13
18
|
return {
|
|
14
19
|
signal: () => ({
|
|
@@ -48,6 +53,24 @@ function cleanupSleepResolvers(internals, workflowId) {
|
|
|
48
53
|
}
|
|
49
54
|
internals.sleepResolversByWorkflow.delete(workflowId);
|
|
50
55
|
}
|
|
56
|
+
function evictSleepResolversWithoutResolving(internals, workflowId) {
|
|
57
|
+
const sleepOps = internals.sleepResolversByWorkflow.get(workflowId);
|
|
58
|
+
if (!sleepOps)
|
|
59
|
+
return;
|
|
60
|
+
for (const operationId of sleepOps)
|
|
61
|
+
internals.sleepResolvers.delete(`${workflowId}:${operationId}`);
|
|
62
|
+
internals.sleepResolversByWorkflow.delete(workflowId);
|
|
63
|
+
}
|
|
64
|
+
function cleanupConditionWaiters(internals, workflowId) {
|
|
65
|
+
const resolver = internals.conditionWaiters.get(workflowId);
|
|
66
|
+
if (!resolver)
|
|
67
|
+
return;
|
|
68
|
+
resolver();
|
|
69
|
+
internals.conditionWaiters.delete(workflowId);
|
|
70
|
+
}
|
|
71
|
+
function evictConditionWaitersWithoutResolving(internals, workflowId) {
|
|
72
|
+
internals.conditionWaiters.delete(workflowId);
|
|
73
|
+
}
|
|
51
74
|
function cleanupReviewEscalations(internals, workflowId, callbacks) {
|
|
52
75
|
const reviewIds = internals.workflowReviewIds.get(workflowId);
|
|
53
76
|
if (!reviewIds)
|
|
@@ -68,15 +91,25 @@ export function cleanupWaiters(internals, workflowId, callbacks) {
|
|
|
68
91
|
for (const kind of TRACKED_WAITER_KINDS)
|
|
69
92
|
cleanupTrackedWaiter(internals, workflowId, kind);
|
|
70
93
|
cleanupSleepResolvers(internals, workflowId);
|
|
94
|
+
cleanupConditionWaiters(internals, workflowId);
|
|
71
95
|
cleanupReviewEscalations(internals, workflowId, callbacks);
|
|
96
|
+
internals.deliveredPendingUpdateIds.delete(workflowId);
|
|
72
97
|
internals.workflowNestingDepths.delete(workflowId);
|
|
73
98
|
internals.workflowHeaders.delete(workflowId);
|
|
74
99
|
internals.workflowServices.delete(workflowId);
|
|
75
100
|
internals.workflowTypeByWorkflowId.delete(workflowId);
|
|
76
101
|
}
|
|
102
|
+
export function evictSuspendedWorkflowWaiters(internals, workflowId, callbacks) {
|
|
103
|
+
for (const kind of TRACKED_WAITER_KINDS)
|
|
104
|
+
cleanupTrackedWaiter(internals, workflowId, kind);
|
|
105
|
+
evictSleepResolversWithoutResolving(internals, workflowId);
|
|
106
|
+
evictConditionWaitersWithoutResolving(internals, workflowId);
|
|
107
|
+
cleanupReviewEscalations(internals, workflowId, callbacks);
|
|
108
|
+
}
|
|
77
109
|
export async function cleanupWorkflowStorage(internals, workflowId, includeOutputArtifacts) {
|
|
78
110
|
const encodedWorkflowId = encodeStorageKeyComponent(workflowId), prefixes = [
|
|
79
111
|
KEYS.activityReconciliationPrefix(workflowId),
|
|
112
|
+
KEYS.childCancellationPrefix(workflowId),
|
|
80
113
|
asyncActivityWorkflowPrefix(workflowId),
|
|
81
114
|
KEYS.signalAcceptedResponsePrefix(workflowId),
|
|
82
115
|
`sig:${encodedWorkflowId}:`,
|
|
@@ -87,7 +120,10 @@ export async function cleanupWorkflowStorage(internals, workflowId, includeOutpu
|
|
|
87
120
|
prefixes.push(`offload:${encodedWorkflowId}:`, `blob:${encodedWorkflowId}:`);
|
|
88
121
|
await internals.storage.delete(KEYS.workflowHeaders(workflowId));
|
|
89
122
|
await internals.storage.delete(KEYS.signalSequence(workflowId));
|
|
123
|
+
await releaseWorkflowConcurrencySlot(internals, workflowId);
|
|
90
124
|
await internals.storage.delete(KEYS.workflowHasServices(workflowId));
|
|
125
|
+
if (!await storageHas(internals.storage, KEYS.teardownOwed(workflowId)))
|
|
126
|
+
await internals.storage.delete(KEYS.finalizerState(workflowId));
|
|
91
127
|
if (internals.storage.deletePrefix) {
|
|
92
128
|
for (const prefix of prefixes)
|
|
93
129
|
await internals.storage.deletePrefix(prefix);
|
|
@@ -114,12 +150,18 @@ export function cleanupTerminalWorkflowMemory(internals, workflowId, callbacks)
|
|
|
114
150
|
forgetCommittedCheckpointBytes(internals, workflowId);
|
|
115
151
|
internals.checkpoints.delete(workflowId);
|
|
116
152
|
internals.heartbeatDetails.delete(workflowId);
|
|
153
|
+
internals.lastHeartbeatDetailsByStep.delete(workflowId);
|
|
117
154
|
for (const [token, pending] of internals.pendingAsyncActivities)
|
|
118
155
|
if (pending.workflowId === workflowId)
|
|
119
156
|
internals.pendingAsyncActivities.delete(token);
|
|
120
157
|
internals.eventLogHeads.delete(workflowId);
|
|
121
158
|
internals.pendingTimelineEntries.delete(workflowId);
|
|
159
|
+
internals.pendingAsyncActivityResolutions ??= new Map;
|
|
160
|
+
internals.pendingAsyncActivityResolutions.delete(workflowId);
|
|
161
|
+
internals.pendingAtomicWorkflowCommitSideEffects ??= new Map;
|
|
162
|
+
internals.pendingAtomicWorkflowCommitSideEffects.delete(workflowId);
|
|
122
163
|
internals.parkedInlineWorkflows.delete(workflowId);
|
|
164
|
+
internals.inlineStrategy?.clearParkedContext(workflowId);
|
|
123
165
|
internals.workflowVersionTuples.delete(workflowId);
|
|
124
166
|
internals.cancelHandlersByWorkflow.delete(workflowId);
|
|
125
167
|
internals.workflowFeedListeners.delete(workflowFeedListenerKey(workflowId, "events"));
|
|
@@ -18,15 +18,22 @@ import {
|
|
|
18
18
|
} from "../attributes-tags.js";
|
|
19
19
|
import { TERMINAL_CLEANUP_DELAY_MS } from "../bulk-operations.js";
|
|
20
20
|
import { takeCancelHandlers } from "../cancel-handlers.js";
|
|
21
|
+
import { pendingAtomicWorkflowCommitSideEffectsStagePut } from "../checkpoint-side-effects.js";
|
|
21
22
|
import { getWorkflowExecutionStartedAt } from "../handles.js";
|
|
22
23
|
import { dropQueuedInlineWorkflowStart } from "../inline-launch-queue.js";
|
|
23
24
|
import { EMPTY_STORAGE_VALUE } from "../lifecycle.js";
|
|
24
|
-
import {
|
|
25
|
+
import {
|
|
26
|
+
createTeardownTimerId,
|
|
27
|
+
createTerminalCleanupTimerId,
|
|
28
|
+
summarizeTimelineValue
|
|
29
|
+
} from "../state-utilities.js";
|
|
30
|
+
import { releaseWorkflowConcurrencySlot } from "../workflow-concurrency.js";
|
|
25
31
|
import { buildWorkflowVisibilityIndexTransition } from "../workflow-indexes.js";
|
|
26
32
|
import {
|
|
27
33
|
cleanupTerminalWorkflowImmediately,
|
|
28
34
|
cleanupTerminalWorkflowSynchronously,
|
|
29
|
-
finalizeScheduledWorkflowTerminal
|
|
35
|
+
finalizeScheduledWorkflowTerminal,
|
|
36
|
+
FORCIBLY_TERMINABLE_STATUSES
|
|
30
37
|
} from "./cleanup.js";
|
|
31
38
|
async function runCancelHandlers(handlers, callbacks, workflowId) {
|
|
32
39
|
for (const handler of handlers)
|
|
@@ -53,17 +60,26 @@ export async function terminateWorkflow(internals, workflowId, status, callbacks
|
|
|
53
60
|
dropQueuedInlineWorkflowStart(internals, workflowId);
|
|
54
61
|
internals.strategy.cancelWorkflow(workflowId);
|
|
55
62
|
try {
|
|
56
|
-
const attributeBytes = await internals.storage.get(KEYS.attribute(workflowId)), attributes = attributeBytes ? decode(attributeBytes) : {}, retainedAttributes = buildRetainedTerminalSearchAttributes(attributes), terminationMessage = status === "timed-out" ? "Workflow timed out" : "Workflow cancelled", terminationResult = await updateWorkflowState(internals, workflowId, {
|
|
57
|
-
|
|
63
|
+
const terminalCleanupToken = internals.workflowsNeedingTerminalCleanup.has(workflowId) ? crypto.randomUUID() : void 0, attributeBytes = await internals.storage.get(KEYS.attribute(workflowId)), attributes = attributeBytes ? decode(attributeBytes) : {}, finalizerStatePresent = await internals.storage.get(KEYS.finalizerState(workflowId)) !== null || pendingAtomicWorkflowCommitSideEffectsStagePut(internals, workflowId, KEYS.finalizerState(workflowId)), retainedAttributes = buildRetainedTerminalSearchAttributes(attributes), terminationMessage = status === "timed-out" ? "Workflow timed out" : "Workflow cancelled", terminationResult = await updateWorkflowState(internals, workflowId, {
|
|
64
|
+
status,
|
|
65
|
+
...reason !== void 0 ? { terminationReason: reason } : {},
|
|
66
|
+
...terminalCleanupToken !== void 0 ? { terminalCleanupToken } : {}
|
|
67
|
+
}, {
|
|
68
|
+
allowedStatuses: FORCIBLY_TERMINABLE_STATUSES,
|
|
58
69
|
buildAdditionalOperations: (_previousState, updatedAt) => {
|
|
59
70
|
finalizePendingTimelineEntry(internals, workflowId, status, terminationMessage, updatedAt);
|
|
60
71
|
const pendingTimelineOperation = buildPendingTimelineOperation(internals, workflowId);
|
|
61
|
-
return
|
|
72
|
+
return [
|
|
73
|
+
...pendingTimelineOperation ? [pendingTimelineOperation] : [],
|
|
74
|
+
...terminalCleanupToken !== void 0 ? buildTerminalCleanupTimerOperations(internals, workflowId, !0, updatedAt, terminalCleanupToken) : [],
|
|
75
|
+
...buildTeardownOperations(workflowId, finalizerStatePresent, updatedAt)
|
|
76
|
+
];
|
|
62
77
|
}
|
|
63
78
|
});
|
|
64
79
|
if (!terminationResult)
|
|
65
80
|
return;
|
|
66
81
|
await runCancellationHandlersForStatus(internals, workflowId, status, callbacks);
|
|
82
|
+
await releaseWorkflowConcurrencySlot(internals, workflowId);
|
|
67
83
|
const { previousState, updatedAt } = terminationResult, elapsed = updatedAt - getWorkflowExecutionStartedAt(previousState);
|
|
68
84
|
await cleanupAttributeIndex(internals, workflowId, attributes);
|
|
69
85
|
await writeRetainedTerminalSearchAttributes(internals, workflowId, retainedAttributes);
|
|
@@ -164,11 +180,14 @@ export async function completeWorkflow(internals, workflowId, result, callbacks)
|
|
|
164
180
|
appendSearchAttributeOperations(completionOperations, workflowId, currentAttributes);
|
|
165
181
|
if (terminalCleanupToken !== void 0)
|
|
166
182
|
completionOperations.push(...buildTerminalCleanupTimerOperations(internals, workflowId, !1, now, terminalCleanupToken));
|
|
167
|
-
await callbacks.commitWorkflowStateOperations(state, completionOperations
|
|
183
|
+
await callbacks.commitWorkflowStateOperations(state, completionOperations, {
|
|
184
|
+
includePendingAtomicSideEffects: !0
|
|
185
|
+
});
|
|
168
186
|
return { duration };
|
|
169
187
|
});
|
|
170
188
|
if (!completionMetadata)
|
|
171
189
|
return;
|
|
190
|
+
await releaseWorkflowConcurrencySlot(internals, workflowId);
|
|
172
191
|
notifyCompletionWaiters(internals, workflowId, result, completionMetadata.duration, callbacks);
|
|
173
192
|
}
|
|
174
193
|
export async function failWorkflow(internals, workflowId, error, callbacks, failureCategory = "system") {
|
|
@@ -178,18 +197,24 @@ export async function failWorkflow(internals, workflowId, error, callbacks, fail
|
|
|
178
197
|
status: "failed",
|
|
179
198
|
error: error.message,
|
|
180
199
|
failureCategory
|
|
181
|
-
};
|
|
200
|
+
}, terminalCleanupToken = internals.workflowsNeedingTerminalCleanup.has(workflowId) ? crypto.randomUUID() : void 0;
|
|
182
201
|
if (error.stack !== void 0)
|
|
183
202
|
stateUpdate.errorStack = error.stack;
|
|
203
|
+
if (terminalCleanupToken !== void 0)
|
|
204
|
+
stateUpdate.terminalCleanupToken = terminalCleanupToken;
|
|
184
205
|
if (!await updateWorkflowState(internals, workflowId, stateUpdate, {
|
|
185
|
-
allowedStatuses:
|
|
206
|
+
allowedStatuses: FORCIBLY_TERMINABLE_STATUSES,
|
|
186
207
|
buildAdditionalOperations: (_previousState, updatedAt) => {
|
|
187
208
|
finalizePendingTimelineEntry(internals, workflowId, "failed", error.message, updatedAt);
|
|
188
209
|
const pendingTimelineOperation = buildPendingTimelineOperation(internals, workflowId);
|
|
189
|
-
return
|
|
210
|
+
return [
|
|
211
|
+
...pendingTimelineOperation ? [pendingTimelineOperation] : [],
|
|
212
|
+
...terminalCleanupToken !== void 0 ? buildTerminalCleanupTimerOperations(internals, workflowId, !1, updatedAt, terminalCleanupToken) : []
|
|
213
|
+
];
|
|
190
214
|
}
|
|
191
215
|
}))
|
|
192
216
|
return;
|
|
217
|
+
await releaseWorkflowConcurrencySlot(internals, workflowId);
|
|
193
218
|
await cleanupAttributeIndex(internals, workflowId, attributes);
|
|
194
219
|
callbacks.swallowPromiseRejection(internals.scheduler.cancel(`deadline:${workflowId}`, workflowId));
|
|
195
220
|
await writeRetainedTerminalSearchAttributes(internals, workflowId, retainedAttributes);
|
|
@@ -218,6 +243,20 @@ export function buildTerminalCleanupTimerOperations(_internals, workflowId, incl
|
|
|
218
243
|
kind: "terminal-cleanup"
|
|
219
244
|
});
|
|
220
245
|
}
|
|
246
|
+
function buildTeardownOperations(workflowId, finalizerStatePresent, terminalizedAt) {
|
|
247
|
+
if (!finalizerStatePresent)
|
|
248
|
+
return [];
|
|
249
|
+
const token = crypto.randomUUID(), claim = { status: "owed", attempts: 0, token };
|
|
250
|
+
return [
|
|
251
|
+
{ type: "put", key: KEYS.teardownOwed(workflowId), value: encode(claim) },
|
|
252
|
+
...buildTimerBatchOperations({
|
|
253
|
+
id: createTeardownTimerId(token),
|
|
254
|
+
workflowId,
|
|
255
|
+
fireAt: terminalizedAt,
|
|
256
|
+
kind: "teardown"
|
|
257
|
+
})
|
|
258
|
+
];
|
|
259
|
+
}
|
|
221
260
|
export async function ensureTerminalCleanupTracked(internals, workflowId) {
|
|
222
261
|
if (internals.workflowsNeedingTerminalCleanup.has(workflowId))
|
|
223
262
|
return;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `runFinalizerActivity` primitive (#446 Phase 2). A workflow's definition-level
|
|
3
|
+
* `finalizer` is an ordinary activity, but it runs POST-terminal — after the engine
|
|
4
|
+
* has evicted the workflow's generator and abort controller — so it cannot go through
|
|
5
|
+
* the live-workflow `executeActivity` path: that path reads
|
|
6
|
+
* `inlineStrategy.getAbortController(workflowId)` (gone after cancel) and the
|
|
7
|
+
* per-workflow type/heartbeat bookkeeping (swept by terminal cleanup). This primitive
|
|
8
|
+
* therefore owns its OWN `AbortController`, resolves the implementation from the
|
|
9
|
+
* engine-lifetime registration entry, and never touches the operation-result feedback
|
|
10
|
+
* channel.
|
|
11
|
+
*
|
|
12
|
+
* Outer retry/backoff is the teardown timer reschedule in `runWorkflowFinalizer`, NOT
|
|
13
|
+
* the activity's own `retry` policy — so this primitive runs exactly one attempt and
|
|
14
|
+
* surfaces success or a thrown error to the caller. The activity's `timeout` is honored
|
|
15
|
+
* as a per-attempt cap.
|
|
16
|
+
*
|
|
17
|
+
* @module core/engine/termination/finalizer-activity
|
|
18
|
+
*/
|
|
19
|
+
import type { ActivityContext, Duration } from '../../types.ts';
|
|
20
|
+
/**
|
|
21
|
+
* The minimal finalizer shape this primitive uses. A registered finalizer is stored
|
|
22
|
+
* as `AnyActivityDefinition`, whose `execute` is typed `ActivityFunction<never>` (the
|
|
23
|
+
* input is contravariantly `never`) and which erases `timeout` at the type level —
|
|
24
|
+
* neither shape is directly invokable with `unknown` input. The drive narrows the
|
|
25
|
+
* registry entry to this structural type, which is what the engine actually relies on
|
|
26
|
+
* at teardown: a named, callable activity with an optional per-attempt `timeout`.
|
|
27
|
+
*/
|
|
28
|
+
export interface RunnableFinalizer {
|
|
29
|
+
readonly name: string;
|
|
30
|
+
readonly timeout?: Duration;
|
|
31
|
+
execute(input: unknown, context?: ActivityContext): unknown;
|
|
32
|
+
}
|
|
33
|
+
/** Outcome of a single finalizer attempt. */
|
|
34
|
+
export type FinalizerAttemptResult = {
|
|
35
|
+
ok: true;
|
|
36
|
+
} | {
|
|
37
|
+
ok: false;
|
|
38
|
+
error: unknown;
|
|
39
|
+
abortedByShutdown: boolean;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Run one attempt of a workflow's finalizer activity against the recorded finalizer
|
|
43
|
+
* state, under a caller-supplied abort signal (the engine shutdown signal) composed
|
|
44
|
+
* with the activity's own per-attempt timeout. Resolves to a structured result rather
|
|
45
|
+
* than throwing, so the drive can branch on success / retryable-failure / dead-letter
|
|
46
|
+
* without a try/catch around it.
|
|
47
|
+
*
|
|
48
|
+
* @param finalizer - the resolved finalizer activity definition (from the engine-lifetime registry)
|
|
49
|
+
* @param input - the decoded `ctx.setFinalizerState` payload passed as the activity input
|
|
50
|
+
* @param attempt - 1-based attempt number, for the per-attempt timeout error message
|
|
51
|
+
* @param shutdownSignal - the engine's dispose/shutdown abort signal; aborting it stops a cooperating finalizer
|
|
52
|
+
*/
|
|
53
|
+
export declare function runFinalizerActivity(finalizer: RunnableFinalizer, input: unknown, attempt: number, shutdownSignal: AbortSignal): Promise<FinalizerAttemptResult>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { parseDuration } from "../../scheduler.js";
|
|
2
|
+
import { withPerAttemptTimeout } from "../activity-per-attempt-timeout.js";
|
|
3
|
+
export async function runFinalizerActivity(finalizer, input, attempt, shutdownSignal) {
|
|
4
|
+
const perAttemptTimeoutMs = finalizer.timeout === void 0 ? void 0 : parseDuration(finalizer.timeout), attemptController = new AbortController, relayShutdownAbort = () => attemptController.abort(shutdownSignal.reason);
|
|
5
|
+
if (shutdownSignal.aborted)
|
|
6
|
+
attemptController.abort(shutdownSignal.reason);
|
|
7
|
+
else
|
|
8
|
+
shutdownSignal.addEventListener("abort", relayShutdownAbort, { once: !0 });
|
|
9
|
+
const activityContext = {
|
|
10
|
+
signal: attemptController.signal,
|
|
11
|
+
heartbeat: () => {},
|
|
12
|
+
completeAsync: () => {
|
|
13
|
+
throw Error(`Finalizer "${finalizer.name}" called ctx.completeAsync(), which is not supported in a workflow finalizer: the finalizer runs after the workflow is already terminal, so there is no durable step to complete out of band. Run the teardown synchronously instead.`);
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
try {
|
|
17
|
+
await withPerAttemptTimeout(finalizer.execute(input, activityContext), perAttemptTimeoutMs, finalizer.name, attempt, attemptController);
|
|
18
|
+
if (shutdownSignal.aborted)
|
|
19
|
+
return {
|
|
20
|
+
ok: !1,
|
|
21
|
+
error: Error(`Finalizer "${finalizer.name}" resolved while the engine was shutting down; treating attempt ${attempt} as shutdown-aborted so the teardown re-runs after restart.`, { cause: shutdownSignal.reason }),
|
|
22
|
+
abortedByShutdown: !0
|
|
23
|
+
};
|
|
24
|
+
return { ok: !0 };
|
|
25
|
+
} catch (error) {
|
|
26
|
+
return { ok: !1, error, abortedByShutdown: shutdownSignal.aborted };
|
|
27
|
+
} finally {
|
|
28
|
+
shutdownSignal.removeEventListener("abort", relayShutdownAbort);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Durable-claim mechanics for the workflow finalizer drive (issue #446 Phase 2).
|
|
3
|
+
* This module owns the `teardownOwed` marker's lifecycle — the stale-claim reclaim
|
|
4
|
+
* horizon, the retry backoff schedule, the dead-letter record shape, and every fenced
|
|
5
|
+
* write that mutates the marker (claim CAS, settle CAS, re-arm, clear, dead-letter). The
|
|
6
|
+
* orchestration that decides WHEN to call these lives in `./finalizer.ts`; keeping the
|
|
7
|
+
* byte-level claim transitions here keeps each module under the size budget and isolates
|
|
8
|
+
* the part where CAS correctness matters most.
|
|
9
|
+
*
|
|
10
|
+
* Concurrency contract (see `./finalizer.ts` for the full model): a holder fenced-CAS's
|
|
11
|
+
* `owed → running` (stamping `claimedAt`) before running the finalizer, then settle-CAS's
|
|
12
|
+
* the EXACT `running` bytes it wrote when clearing, rescheduling, or dead-lettering — so a
|
|
13
|
+
* concurrent reclaimer can never clobber a fresher claim. Liveness is decided purely by
|
|
14
|
+
* the clock via {@link teardownStaleThresholdMs}.
|
|
15
|
+
*
|
|
16
|
+
* @module core/engine/termination/finalizer-claim
|
|
17
|
+
*/
|
|
18
|
+
import type { BatchOperation } from '../../../storage/interface.ts';
|
|
19
|
+
import type { EngineInternals } from '../internals.ts';
|
|
20
|
+
import { type TeardownClaim } from '../state-utilities.ts';
|
|
21
|
+
import type { RunnableFinalizer } from './finalizer-activity.ts';
|
|
22
|
+
/** Maximum finalizer attempts before the teardown is dead-lettered (the leak horizon). */
|
|
23
|
+
export declare const MAX_TEARDOWN_ATTEMPTS = 8;
|
|
24
|
+
/** Short re-arm delay for the self-heal timer written on a non-settling drive exit. */
|
|
25
|
+
export declare const TEARDOWN_SELF_HEAL_DELAY_MS = 30000;
|
|
26
|
+
/** Backoff for the timer rescheduled after a failed finalizer attempt (1-based attempt). */
|
|
27
|
+
export declare function teardownBackoffMs(failedAttempt: number): number;
|
|
28
|
+
/**
|
|
29
|
+
* The reclaim horizon for a `running` claim: a holder that has not settled within this
|
|
30
|
+
* window of `claimedAt` is presumed crashed/deposed and its claim is reclaimable. Equal
|
|
31
|
+
* to the finalizer's per-attempt budget (its declared `timeout`, or
|
|
32
|
+
* {@link DEFAULT_FINALIZER_STALE_BUDGET_MS}) plus {@link TEARDOWN_STALE_MARGIN_MS}.
|
|
33
|
+
*/
|
|
34
|
+
export declare function teardownStaleThresholdMs(finalizer: RunnableFinalizer): number;
|
|
35
|
+
/** Whether a `running` claim is reclaimable: its holder has not settled within the stale window. */
|
|
36
|
+
export declare function runningClaimIsStale(internals: EngineInternals, claim: TeardownClaim, finalizer: RunnableFinalizer): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Durable audit record written to {@link KEYS.teardownDeadLetter} when a workflow's
|
|
39
|
+
* finalizer permanently fails — the retry horizon was reached, or the recorded resource
|
|
40
|
+
* state vanished so the finalizer can never run. It is the supported operator surface
|
|
41
|
+
* for a leaked external resource: raw storage inspection of the `wf-teardown-deadletter:`
|
|
42
|
+
* key is the contract (in-process teardown events are best-effort and not durable, and
|
|
43
|
+
* the record is excluded from the workflow purge delete-set so it survives after the
|
|
44
|
+
* workflow record is gone).
|
|
45
|
+
*/
|
|
46
|
+
export interface TeardownDeadLetterRecord {
|
|
47
|
+
/** The workflow type whose finalizer leaked. */
|
|
48
|
+
type: string;
|
|
49
|
+
/** The last finalizer error message (or the reason teardown was abandoned). */
|
|
50
|
+
lastError: string;
|
|
51
|
+
/** The attempt count reached before dead-lettering. */
|
|
52
|
+
attempts: number;
|
|
53
|
+
/** Engine clock when the record was written. */
|
|
54
|
+
deadLetteredAt: number;
|
|
55
|
+
/** The decoded `ctx.setFinalizerState` payload, when it was still recoverable. */
|
|
56
|
+
finalizerInput?: unknown;
|
|
57
|
+
}
|
|
58
|
+
/** Build the operations that arm a fresh `wf-teardown:` timer at `fireAt` (same token). */
|
|
59
|
+
export declare function teardownTimerOperations(token: string, workflowId: string, fireAt: number): BatchOperation[];
|
|
60
|
+
/** Encode an `owed` claim (attempts as given, no `claimedAt` while owed). */
|
|
61
|
+
export declare function encodeOwedClaim(attempts: number, token: string): Uint8Array;
|
|
62
|
+
/** Encode the `running` claim a holder writes to atomically claim the marker. */
|
|
63
|
+
export declare function encodeRunningClaim(attempts: number, token: string, claimedAt: number): Uint8Array;
|
|
64
|
+
/**
|
|
65
|
+
* Re-arm a future `wf-teardown:` timer for a non-settling drive exit (lost CAS, a
|
|
66
|
+
* presumed-live `running` claim, a shutdown abort, or a leave-the-marker case), so the
|
|
67
|
+
* claim is not stranded after the scheduler deletes the fired timer. The marker bytes
|
|
68
|
+
* are left untouched — only the timer is (re)written. Fenced, best-effort: a deposed
|
|
69
|
+
* engine that loses the fence simply yields to the new owner, whose own timer drives it.
|
|
70
|
+
*/
|
|
71
|
+
export declare function rearmTeardownTimer(internals: EngineInternals, workflowId: string, token: string, delayMs: number): Promise<void>;
|
|
72
|
+
/**
|
|
73
|
+
* Clear the teardown marker for a workflow that turned out not to owe a finalizer run
|
|
74
|
+
* after all — a stale timer or a vanished/ineligible workflow. Conditioned on the marker
|
|
75
|
+
* still being byte-for-byte `expectedBytes` (the bytes this drive read), so a concurrent
|
|
76
|
+
* drive that already re-claimed or re-armed the marker — e.g. a same-id rerun whose fresh
|
|
77
|
+
* cancellation wrote a NEW claim — is never clobbered. A lost CAS (someone changed it
|
|
78
|
+
* first) is a benign no-op. Swallows a lost-fence error: a deposed engine simply leaves
|
|
79
|
+
* the marker for the new owner. No timer is re-armed: clearing the marker IS the settle.
|
|
80
|
+
*/
|
|
81
|
+
export declare function clearTeardownMarker(internals: EngineInternals, workflowId: string, expectedBytes: Uint8Array): Promise<boolean>;
|
|
82
|
+
/**
|
|
83
|
+
* Atomically claim the marker: CAS `owed → running` only if it is byte-for-byte the
|
|
84
|
+
* `expectedBytes` we read (so concurrent reclaimers can't both win), fenced on the lease
|
|
85
|
+
* epoch. Returns the `running` bytes we wrote on success (needed as the settle CAS
|
|
86
|
+
* precondition), or `null` on a lost CAS.
|
|
87
|
+
*/
|
|
88
|
+
export declare function claimTeardownMarker(internals: EngineInternals, workflowId: string, expectedBytes: Uint8Array, attempts: number, token: string): Promise<Uint8Array | null>;
|
|
89
|
+
/**
|
|
90
|
+
* Commit a settle batch conditioned on the `teardownOwed` marker still equalling the
|
|
91
|
+
* exact `running` bytes this drive wrote (Codex MF2). If a reclaimer overwrote the
|
|
92
|
+
* marker first, the CAS fails and this returns `false` WITHOUT committing — the caller
|
|
93
|
+
* must then skip dispatching any teardown event. A deposition still hard-halts (the
|
|
94
|
+
* fenced helper throws), which the drive's outer try/catch routes to a cleanup error.
|
|
95
|
+
*/
|
|
96
|
+
export declare function settleOnRunningClaim(internals: EngineInternals, workflowId: string, runningBytes: Uint8Array, operations: BatchOperation[]): Promise<boolean>;
|
|
97
|
+
/**
|
|
98
|
+
* Write the durable dead-letter record and clear the teardown + finalizer-state keys,
|
|
99
|
+
* conditioned on the marker still being byte-for-byte `expectedBytes`. Used both at the
|
|
100
|
+
* retry horizon (`expectedBytes` = the `running` bytes this drive wrote) and when the
|
|
101
|
+
* recorded resource state vanished before any claim (`expectedBytes` = the `owed` bytes
|
|
102
|
+
* this drive read). Conditioning on `expectedBytes` in BOTH cases prevents a stale drive
|
|
103
|
+
* from dead-lettering after a concurrent drive already settled the marker — which would
|
|
104
|
+
* falsely report a leak after a successful teardown. Returns whether the durable write
|
|
105
|
+
* committed; the caller dispatches the dead-lettered event only when it did.
|
|
106
|
+
*/
|
|
107
|
+
export declare function deadLetterTeardown(internals: EngineInternals, workflowId: string, workflowType: string, attempts: number, expectedBytes: Uint8Array, details: {
|
|
108
|
+
lastError: string;
|
|
109
|
+
finalizerInput: unknown;
|
|
110
|
+
}): Promise<boolean>;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { KEYS } from "../../../storage/interface.js";
|
|
2
|
+
import { encode } from "../../codec.js";
|
|
3
|
+
import { buildTimerBatchOperations, parseDuration } from "../../scheduler.js";
|
|
4
|
+
import {
|
|
5
|
+
commitFencedEngineWrite,
|
|
6
|
+
commitFencedEngineWriteAllowingPreconditionFailure
|
|
7
|
+
} from "../fenced-write.js";
|
|
8
|
+
import { createTeardownTimerId } from "../state-utilities.js";
|
|
9
|
+
export const MAX_TEARDOWN_ATTEMPTS = 8;
|
|
10
|
+
const TEARDOWN_BACKOFF_SCHEDULE_MS = [
|
|
11
|
+
60000,
|
|
12
|
+
300000,
|
|
13
|
+
900000,
|
|
14
|
+
3600000
|
|
15
|
+
], DEFAULT_FINALIZER_STALE_BUDGET_MS = 300000, TEARDOWN_STALE_MARGIN_MS = 30000;
|
|
16
|
+
export const TEARDOWN_SELF_HEAL_DELAY_MS = 30000;
|
|
17
|
+
export function teardownBackoffMs(failedAttempt) {
|
|
18
|
+
const index = failedAttempt - 1;
|
|
19
|
+
return TEARDOWN_BACKOFF_SCHEDULE_MS[index] ?? TEARDOWN_BACKOFF_SCHEDULE_MS[TEARDOWN_BACKOFF_SCHEDULE_MS.length - 1];
|
|
20
|
+
}
|
|
21
|
+
export function teardownStaleThresholdMs(finalizer) {
|
|
22
|
+
return (finalizer.timeout === void 0 ? DEFAULT_FINALIZER_STALE_BUDGET_MS : parseDuration(finalizer.timeout)) + TEARDOWN_STALE_MARGIN_MS;
|
|
23
|
+
}
|
|
24
|
+
export function runningClaimIsStale(internals, claim, finalizer) {
|
|
25
|
+
if (claim.status !== "running")
|
|
26
|
+
return !0;
|
|
27
|
+
if (claim.claimedAt === void 0)
|
|
28
|
+
return !0;
|
|
29
|
+
return internals.options.getNow() - claim.claimedAt >= teardownStaleThresholdMs(finalizer);
|
|
30
|
+
}
|
|
31
|
+
export function teardownTimerOperations(token, workflowId, fireAt) {
|
|
32
|
+
return buildTimerBatchOperations({
|
|
33
|
+
id: createTeardownTimerId(token),
|
|
34
|
+
workflowId,
|
|
35
|
+
fireAt,
|
|
36
|
+
kind: "teardown"
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
export function encodeOwedClaim(attempts, token) {
|
|
40
|
+
return encode({ status: "owed", attempts, token });
|
|
41
|
+
}
|
|
42
|
+
export function encodeRunningClaim(attempts, token, claimedAt) {
|
|
43
|
+
return encode({ status: "running", attempts, token, claimedAt });
|
|
44
|
+
}
|
|
45
|
+
export async function rearmTeardownTimer(internals, workflowId, token, delayMs) {
|
|
46
|
+
const fireAt = internals.options.getNow() + delayMs;
|
|
47
|
+
try {
|
|
48
|
+
await commitFencedEngineWrite(internals, teardownTimerOperations(token, workflowId, fireAt), [], () => Error("teardown self-heal re-arm lost the lease fence"));
|
|
49
|
+
} catch {}
|
|
50
|
+
}
|
|
51
|
+
export async function clearTeardownMarker(internals, workflowId, expectedBytes) {
|
|
52
|
+
try {
|
|
53
|
+
return await commitFencedEngineWriteAllowingPreconditionFailure(internals, [{ type: "delete", key: KEYS.teardownOwed(workflowId) }], [{ key: KEYS.teardownOwed(workflowId), expectedValue: expectedBytes }]);
|
|
54
|
+
} catch {
|
|
55
|
+
return !1;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
export async function claimTeardownMarker(internals, workflowId, expectedBytes, attempts, token) {
|
|
59
|
+
const runningBytes = encodeRunningClaim(attempts, token, internals.options.getNow());
|
|
60
|
+
return await commitFencedEngineWriteAllowingPreconditionFailure(internals, [{ type: "put", key: KEYS.teardownOwed(workflowId), value: runningBytes }], [{ key: KEYS.teardownOwed(workflowId), expectedValue: expectedBytes }]) ? runningBytes : null;
|
|
61
|
+
}
|
|
62
|
+
export async function settleOnRunningClaim(internals, workflowId, runningBytes, operations) {
|
|
63
|
+
return commitFencedEngineWriteAllowingPreconditionFailure(internals, operations, [
|
|
64
|
+
{ key: KEYS.teardownOwed(workflowId), expectedValue: runningBytes }
|
|
65
|
+
]);
|
|
66
|
+
}
|
|
67
|
+
export async function deadLetterTeardown(internals, workflowId, workflowType, attempts, expectedBytes, details) {
|
|
68
|
+
const deadLetter = {
|
|
69
|
+
type: workflowType,
|
|
70
|
+
lastError: details.lastError,
|
|
71
|
+
attempts,
|
|
72
|
+
deadLetteredAt: internals.options.getNow(),
|
|
73
|
+
...details.finalizerInput === void 0 ? {} : { finalizerInput: details.finalizerInput }
|
|
74
|
+
};
|
|
75
|
+
return settleOnRunningClaim(internals, workflowId, expectedBytes, [
|
|
76
|
+
{ type: "delete", key: KEYS.teardownOwed(workflowId) },
|
|
77
|
+
{ type: "delete", key: KEYS.finalizerState(workflowId) },
|
|
78
|
+
{ type: "put", key: KEYS.teardownDeadLetter(workflowId), value: encode(deadLetter) }
|
|
79
|
+
]);
|
|
80
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The engine-side finalizer drive (`runWorkflowFinalizer`) for issue #446 Phase 2.
|
|
3
|
+
* Dispatched by the scheduler when a `wf-teardown:` timer fires, it drives a
|
|
4
|
+
* workflow's definition-level `finalizer` to durable completion after a
|
|
5
|
+
* `cancelled`/`timed-out` terminal — claiming the durable teardown marker, running
|
|
6
|
+
* the finalizer activity (via {@link runFinalizerActivity}), and then clearing,
|
|
7
|
+
* backing off, or dead-lettering based on the outcome. The byte-level claim mechanics
|
|
8
|
+
* (CAS, settle, re-arm, dead-letter, the stale horizon and backoff) live in
|
|
9
|
+
* `./finalizer-claim.ts`; this module is the orchestration that decides which to call.
|
|
10
|
+
*
|
|
11
|
+
* Concurrency model — a single durable, TIME-based claim:
|
|
12
|
+
* the durable `teardownOwed` marker carries a `{ status, attempts, token, claimedAt }`
|
|
13
|
+
* claim ({@link TeardownClaim}). A holder fenced-CAS's `owed → running` (stamping
|
|
14
|
+
* `claimedAt`) before running, and settle-CAS's the exact `running` bytes it wrote when
|
|
15
|
+
* clearing or rescheduling — so a concurrent reclaimer can never clobber a fresher
|
|
16
|
+
* claim. Liveness is decided purely by the clock: a `running` claim is reclaimable once
|
|
17
|
+
* `claimedAt` is older than {@link teardownStaleThresholdMs} (the finalizer's per-attempt
|
|
18
|
+
* timeout plus a margin). There is NO in-memory liveness set and NO epoch in the record;
|
|
19
|
+
* crash recovery is an ordinary stale-claim retry driven by the timer that survived the
|
|
20
|
+
* terminal batch. The tradeoff is that a finalizer running past the stale threshold may
|
|
21
|
+
* be re-driven concurrently, which is why workflow finalizers must be idempotent (a
|
|
22
|
+
* contract of the #446 design).
|
|
23
|
+
*
|
|
24
|
+
* Self-heal invariant: every exit that does NOT settle the claim (a lost claim CAS, a
|
|
25
|
+
* presumed-live `running` claim, a shutdown-aborted attempt, or a missing registration)
|
|
26
|
+
* re-arms a future `wf-teardown:` timer before returning, because the scheduler deletes
|
|
27
|
+
* the fired timer once this returns without throwing. A non-settling exit that forgot to
|
|
28
|
+
* re-arm would strand the marker with no timer to re-drive it.
|
|
29
|
+
*
|
|
30
|
+
* @module core/engine/termination/finalizer
|
|
31
|
+
*/
|
|
32
|
+
import type { WorkflowState } from '../../types.ts';
|
|
33
|
+
import type { EngineInternals } from '../internals.ts';
|
|
34
|
+
export { teardownStaleThresholdMs, type TeardownDeadLetterRecord } from './finalizer-claim.ts';
|
|
35
|
+
/** The subset of termination callbacks the finalizer drive needs. */
|
|
36
|
+
export interface FinalizerDriveCallbacks {
|
|
37
|
+
loadWorkflowState: (workflowId: string) => Promise<WorkflowState | null>;
|
|
38
|
+
dispatchEvent: (event: Event) => void;
|
|
39
|
+
handleCleanupError: (source: string, error: unknown, workflowId?: string) => void;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Drive one teardown attempt for a workflow whose `wf-teardown:` timer just fired.
|
|
43
|
+
* Never throws: the scheduler treats a thrown timer callback as "retry on the next
|
|
44
|
+
* tick", which would defeat the backoff schedule, so every failure path is handled
|
|
45
|
+
* internally and the function returns normally (letting the scheduler delete the
|
|
46
|
+
* fired timer; a backoff/self-heal reschedule writes a fresh timer entry).
|
|
47
|
+
*/
|
|
48
|
+
export declare function runWorkflowFinalizer(internals: EngineInternals, workflowId: string, timerId: string, callbacks: FinalizerDriveCallbacks): Promise<void>;
|