@lostgradient/weft 0.3.0 → 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 +79 -24
- package/dist/cli/conformance.js +7 -1
- package/dist/cli/generated/operation-client.generated.d.ts +28 -13
- package/dist/cli/generated/operation-client.generated.js +1 -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 +79 -78
- package/dist/client/handle-delegation.d.ts +3 -2
- package/dist/client/handle-delegation.js +3 -1
- package/dist/client/http-client-requests.d.ts +2 -1
- package/dist/client/http-client-requests.js +7 -0
- package/dist/client/http-client.d.ts +9 -6
- package/dist/client/http-client.js +10 -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 +46 -5
- package/dist/client/local.d.ts +4 -1
- package/dist/client/local.js +12 -4
- package/dist/client/start-body.d.ts +4 -3
- 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 +100 -6
- 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 +9 -5
- package/dist/core/context/index.js +17 -12
- package/dist/core/context/internals.d.ts +20 -0
- package/dist/core/context/internals.js +3 -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 +6 -1
- package/dist/core/context/run-operation.js +41 -87
- 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 -0
- package/dist/core/engine/construction.js +21 -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 +13 -0
- package/dist/core/engine/engine-create-types.d.ts +14 -4
- package/dist/core/engine/engine-internal-types.d.ts +26 -3
- package/dist/core/engine/errors.d.ts +47 -0
- package/dist/core/engine/errors.js +20 -0
- 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/handles.d.ts +8 -0
- package/dist/core/engine/index.d.ts +34 -16
- package/dist/core/engine/index.js +133 -8
- package/dist/core/engine/inline-parking.js +3 -2
- package/dist/core/engine/internals.d.ts +107 -3
- 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/persist.js +10 -32
- 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 +16 -9
- 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 +9 -0
- package/dist/core/engine/lifecycle/start-commit.js +50 -8
- 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.d.ts +3 -2
- package/dist/core/engine/lifecycle/start-or-signal.js +11 -81
- 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 +4 -4
- package/dist/core/engine/lifecycle/start.js +17 -9
- package/dist/core/engine/lifecycle/transition.js +17 -5
- package/dist/core/engine/lifecycle.d.ts +1 -1
- package/dist/core/engine/list-candidate-resolution.js +2 -2
- package/dist/core/engine/listing.js +9 -5
- 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/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-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 +7 -4
- package/dist/core/engine/schedules.js +37 -16
- 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/signals.d.ts +18 -2
- package/dist/core/engine/signals.js +42 -21
- 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 +3 -1
- package/dist/core/engine/termination/cleanup.js +25 -1
- package/dist/core/engine/termination/complete.js +44 -6
- 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 +3 -1
- package/dist/core/engine/termination.d.ts +1 -0
- package/dist/core/engine/termination.js +4 -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 +32 -5
- 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 +4 -5
- 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 +18 -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 +88 -23
- package/dist/core/events/workflow-events.js +26 -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/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 +34 -0
- package/dist/core/start-workflow-validation.js +19 -0
- 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 +80 -61
- package/dist/core/types/bulk.d.ts +50 -9
- package/dist/core/types/checkpoint.d.ts +44 -8
- package/dist/core/types/list-options.d.ts +146 -0
- package/dist/core/types/list-options.js +0 -0
- package/dist/core/types/options.d.ts +121 -165
- package/dist/core/types/schedules.d.ts +39 -3
- package/dist/core/types/services-resolution.d.ts +2 -2
- 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 +42 -11
- 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 +84 -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.d.ts +4 -0
- package/dist/core/types.js +4 -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 +16 -0
- 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/format.js +1 -6
- package/dist/diagnostics/types.d.ts +4 -5
- package/dist/diagnostics/validate.d.ts +0 -1
- package/dist/diagnostics/version-check.d.ts +1 -1
- package/dist/diagnostics/version-check.js +4 -9
- package/dist/index.d.ts +12 -10
- package/dist/index.js +29 -3
- package/dist/json-schema.js +3 -3
- package/dist/mcp/cli.js +27 -27
- package/dist/mcp/dispatcher.js +1 -1
- package/dist/mcp/http.js +16 -6
- 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 +59 -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 +23 -23
- package/dist/server/index.d.ts +32 -2
- package/dist/server/index.js +26 -26
- 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/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 +6 -1
- package/dist/server/operations/start-or-signal-workflow.js +14 -24
- package/dist/server/operations/start-workflow-options.d.ts +6 -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 +8 -23
- 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/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 +3 -1
- package/dist/server/rest-bindings.js +12 -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-polling.js +61 -20
- 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 +38 -30
- package/dist/server/serve-internals.d.ts +3 -1
- package/dist/server/serve-internals.js +18 -2
- package/dist/server/task-state.d.ts +30 -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 +30 -30
- package/dist/storage/auto.js +1 -1
- package/dist/storage/bun-sql.js +24 -0
- 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 +76 -4
- package/dist/storage/indexeddb.js +1 -1
- package/dist/storage/interface.d.ts +163 -0
- package/dist/storage/interface.js +1 -1
- package/dist/storage/key-prefixes.d.ts +1 -1
- package/dist/storage/key-prefixes.js +10 -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 +30 -3
- package/dist/storage/neon-value-mapping.js +12 -0
- package/dist/storage/neon.d.ts +16 -0
- package/dist/storage/neon.js +9 -4
- package/dist/storage/node-sqlite.js +23 -0
- package/dist/storage/postgres-key-value-queries.d.ts +69 -44
- package/dist/storage/postgres-key-value-queries.js +62 -24
- package/dist/storage/resolve.js +1 -1
- package/dist/storage/scoped-storage.js +1 -1
- package/dist/storage/testing.d.ts +168 -0
- package/dist/storage/testing.js +2 -0
- 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 +28 -28
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/worker/protocol.js +1 -1
- 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 +5 -1
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { WeftError } from '../weft-error.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Thrown when `ownership: 'lease'` is configured and the engine cannot acquire the
|
|
4
|
+
* storage lease within the configured wait window — another live instance still
|
|
5
|
+
* holds it. Raised from the lease-acquire step, which runs both inside
|
|
6
|
+
* {@link Engine.create} and at the top of {@link Engine.recoverAll} (so a
|
|
7
|
+
* `new Engine({ ownership: 'lease' })` + `recoverAll()` boot must handle it too).
|
|
8
|
+
* In a rolling deploy this means the
|
|
9
|
+
* outgoing instance has not released the lease (or its lease has not yet expired)
|
|
10
|
+
* within `leaseWaitTimeout`; size that window above the outgoing instance's drain
|
|
11
|
+
* time and above the lease TTL so a crash (no clean release) still resolves once
|
|
12
|
+
* the held lease expires. Inspect `waitedMs` for how long this instance waited
|
|
13
|
+
* and `heldBy` for the holder id observed when it gave up (`null` if unknown).
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* import { EngineLeaseAcquisitionTimeoutError } from '@lostgradient/weft';
|
|
18
|
+
*
|
|
19
|
+
* function isLeaseHandoffStuck(error: unknown): boolean {
|
|
20
|
+
* return error instanceof EngineLeaseAcquisitionTimeoutError;
|
|
21
|
+
* }
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export declare class EngineLeaseAcquisitionTimeoutError extends WeftError<'EngineLeaseAcquisitionTimeoutError'> {
|
|
25
|
+
readonly waitedMs: number;
|
|
26
|
+
readonly heldBy: string | null;
|
|
27
|
+
constructor(waitedMs: number, heldBy: string | null);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Thrown when `ownership: 'lease'` is configured but the lease keys in storage are
|
|
31
|
+
* corrupt. Raised from the lease-acquire step, which runs both inside
|
|
32
|
+
* {@link Engine.create} and at the top of {@link Engine.recoverAll} (so a
|
|
33
|
+
* `new Engine({ ownership: 'lease' })` + `recoverAll()` boot must handle it too) —
|
|
34
|
+
* the `lease:epoch` high-water mark is present
|
|
35
|
+
* but does not decode to a valid epoch, or a holder record exists with no epoch
|
|
36
|
+
* key (which the lease protocol never produces, since `release()` deletes only the
|
|
37
|
+
* holder and never the epoch). The lease epoch is the sole source of truth for the
|
|
38
|
+
* monotonic fencing generation, so a booting instance fails closed rather than
|
|
39
|
+
* re-minting a generation at or below the true high-water mark and risking a
|
|
40
|
+
* split-brain. Resolve by operator repair: delete both `lease:` keys only if you
|
|
41
|
+
* are certain no other instance is running, or reset `lease:epoch` above its last
|
|
42
|
+
* known value.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```ts
|
|
46
|
+
* import { EngineLeaseCorruptedError } from '@lostgradient/weft';
|
|
47
|
+
*
|
|
48
|
+
* function isLeaseCorrupted(error: unknown): boolean {
|
|
49
|
+
* return error instanceof EngineLeaseCorruptedError;
|
|
50
|
+
* }
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export declare class EngineLeaseCorruptedError extends WeftError<'EngineLeaseCorruptedError'> {
|
|
54
|
+
constructor(detail: string);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Thrown by {@link Engine.start} and {@link Engine.startOrSignal} when
|
|
58
|
+
* `ownership: 'lease'` is configured but the engine does not yet hold the lease —
|
|
59
|
+
* it was constructed with `new Engine({ ownership: 'lease' })` and used to start
|
|
60
|
+
* work before `recoverAll()` ran, or created with `recover: false`. In lease mode
|
|
61
|
+
* an engine must hold the single-writer lease (and have recovered existing runs)
|
|
62
|
+
* before it durably writes new workflow state, or a fresh start could race an
|
|
63
|
+
* instance that legitimately owns the store. {@link Engine.create} acquires the
|
|
64
|
+
* lease and recovers for you; a direct constructor must `await engine.recoverAll()`
|
|
65
|
+
* first.
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```ts
|
|
69
|
+
* import { Engine, EngineLeaseNotHeldError } from '@lostgradient/weft';
|
|
70
|
+
*
|
|
71
|
+
* const engine = new Engine({ ownership: 'lease' });
|
|
72
|
+
* try {
|
|
73
|
+
* await engine.start('ping', null);
|
|
74
|
+
* } catch (error) {
|
|
75
|
+
* if (error instanceof EngineLeaseNotHeldError) {
|
|
76
|
+
* await engine.recoverAll(); // acquires the lease, then retry the start
|
|
77
|
+
* }
|
|
78
|
+
* }
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
export declare class EngineLeaseNotHeldError extends WeftError<'EngineLeaseNotHeldError'> {
|
|
82
|
+
constructor();
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Thrown internally on the durable-write path when `ownership: 'lease'` is
|
|
86
|
+
* configured and a fenced write's CAS fails because the held lease epoch is
|
|
87
|
+
* stale — a successor instance has taken the lease and bumped the epoch, so this
|
|
88
|
+
* instance has been deposed. It is the local unwind that stops the commit from
|
|
89
|
+
* advancing in-memory state past a durable write that did not land; the actual
|
|
90
|
+
* "this engine is deposed" reaction (set the `deposed` flag, warn the operator,
|
|
91
|
+
* tear the engine down) is driven by {@link handleDeposition} at the detection
|
|
92
|
+
* site, not by this error propagating — the inline strategy swallows turn
|
|
93
|
+
* rejections, so the throw never reaches a handler. Internal-only: it is never
|
|
94
|
+
* surfaced to user code (deposition reaches operators through the
|
|
95
|
+
* `WeftEngineLeaseLostWarning` process warning).
|
|
96
|
+
*/
|
|
97
|
+
export declare class EngineDeposedError extends WeftError<'EngineDeposedError'> {
|
|
98
|
+
constructor();
|
|
99
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { WeftError } from "../weft-error.js";
|
|
2
|
+
|
|
3
|
+
export class EngineLeaseAcquisitionTimeoutError extends WeftError {
|
|
4
|
+
waitedMs;
|
|
5
|
+
heldBy;
|
|
6
|
+
constructor(waitedMs, heldBy) {
|
|
7
|
+
const heldClause = heldBy === null ? "" : ` (currently held by "${heldBy}")`;
|
|
8
|
+
super("EngineLeaseAcquisitionTimeoutError", `Could not acquire the storage ownership lease within ${waitedMs}ms${heldClause}. Another engine instance still holds it. Increase leaseWaitTimeout above the outgoing instance's drain time and the lease TTL, or ensure the previous instance releases the lease on shutdown.`);
|
|
9
|
+
this.waitedMs = waitedMs;
|
|
10
|
+
this.heldBy = heldBy;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class EngineLeaseCorruptedError extends WeftError {
|
|
15
|
+
constructor(detail) {
|
|
16
|
+
super("EngineLeaseCorruptedError", `The ownership lease state in storage is corrupt and cannot be used safely: ${detail}. Resolve by operator repair (delete both "lease:" keys only if no other instance is running, or reset "lease:epoch" above its last known value).`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export class EngineLeaseNotHeldError extends WeftError {
|
|
21
|
+
constructor() {
|
|
22
|
+
super("EngineLeaseNotHeldError", "ownership: 'lease' requires the engine to hold the lease before starting work. Use `Engine.create({ ownership: \"lease\" })` (which acquires the lease and recovers), or call `await engine.recoverAll()` on a directly-constructed engine before `start()`.");
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export class EngineDeposedError extends WeftError {
|
|
27
|
+
constructor() {
|
|
28
|
+
super("EngineDeposedError", "Engine was deposed: a fenced durable write lost its CAS race because another instance now holds the ownership lease at a newer epoch. This engine is halting.");
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lease-fenced single-writer ownership over a shared durable store. This is the
|
|
3
|
+
* opt-in `Engine.create({ ownership: 'lease' })` mechanism — a CORRECTNESS-PATH
|
|
4
|
+
* coordinator, NOT a best-effort smoke alarm like the second-instance detector.
|
|
5
|
+
* Lease outcomes are acted on, never silently dropped, but the channel differs by
|
|
6
|
+
* phase: a failed acquire THROWS and blocks recovery (corruption fails closed, a
|
|
7
|
+
* timed-out handoff raises a typed error); a renewal reports loss through
|
|
8
|
+
* `onLeaseLost` rather than throwing — a CAS-failed renewal means a successor took
|
|
9
|
+
* the lease ('deposed'), and a transient renewal storage error is tolerated until
|
|
10
|
+
* the lease is too close to lapsing to prove ownership ('renewal-unconfirmable').
|
|
11
|
+
* In Step 1 that loss is observability only (the engine warns); Step 2 will make it
|
|
12
|
+
* enforceable by fencing every durable write on the lease epoch.
|
|
13
|
+
*
|
|
14
|
+
* **Why a lease.** Weft's supported model is one engine process per durable
|
|
15
|
+
* store. Without a lease, a rolling deploy briefly runs two engines (old draining
|
|
16
|
+
* + new booting), both recovering and both issuing at-least-once activities. The
|
|
17
|
+
* lease turns that into a clean handoff: the booting instance ACQUIRES the lease
|
|
18
|
+
* before recovering, the draining instance RELEASES it on dispose, and the new
|
|
19
|
+
* instance only recovers once it owns the lease.
|
|
20
|
+
*
|
|
21
|
+
* **Two-key schema (this is load-bearing, not an optimization).** Ownership is
|
|
22
|
+
* tracked by two keys, never one:
|
|
23
|
+
*
|
|
24
|
+
* - `lease:epoch` — an 8-byte big-endian uint64 fencing token. It changes ONLY on
|
|
25
|
+
* ownership transfer (cold acquire, or a steal/re-acquire after the prior
|
|
26
|
+
* holder's lease lapsed), NEVER on a renewal. It is a monotonic high-water mark
|
|
27
|
+
* that SURVIVES release.
|
|
28
|
+
* - `lease:holder` — a JSON `{ holderId, expiresAt, epoch }` record renewed on
|
|
29
|
+
* every heartbeat (its `expiresAt` advances), so its bytes churn constantly.
|
|
30
|
+
*
|
|
31
|
+
* They are split because `conditionalBatch` compares the WHOLE stored value as
|
|
32
|
+
* bytes. If the epoch lived inside the churning holder record, the fencing token
|
|
33
|
+
* (Step 2) would change on every renewal, spuriously failing the fence and
|
|
34
|
+
* self-terminating healthy holders. Keeping the epoch in its own stable key lets
|
|
35
|
+
* a holder cache its epoch once ({@link LeaseManager.currentEpochBytes}) and use
|
|
36
|
+
* it unchanged as a fencing condition across many renewals.
|
|
37
|
+
*
|
|
38
|
+
* **Epoch monotonicity is the anti-split-brain invariant.** Every transfer
|
|
39
|
+
* conditions on BOTH the holder AND the current epoch and bumps the epoch by one;
|
|
40
|
+
* `release()` deletes ONLY the holder and never the epoch. This guarantees a
|
|
41
|
+
* deposed zombie from generation N can never see its epoch re-minted under it —
|
|
42
|
+
* so once Step 2 fences durable writes on the epoch, the zombie always loses.
|
|
43
|
+
*
|
|
44
|
+
* @module core/engine/lease-manager
|
|
45
|
+
*/
|
|
46
|
+
import { type Storage } from '../../storage/interface.ts';
|
|
47
|
+
/** Why a holder lost its lease — surfaced to {@link LeaseManagerOptions.onLeaseLost}. */
|
|
48
|
+
export type LeaseLostReason = 'deposed' | 'renewal-unconfirmable';
|
|
49
|
+
/** Options for {@link createLeaseManager}. */
|
|
50
|
+
export type LeaseManagerOptions = {
|
|
51
|
+
storage: Storage;
|
|
52
|
+
/** This engine's unique instance id (the lease holder id). */
|
|
53
|
+
holderId: string;
|
|
54
|
+
/** Wall-clock source (ms), injected so tests can advance time deterministically. */
|
|
55
|
+
getNow: () => number;
|
|
56
|
+
/** Lease time-to-live (ms). A stolen lease becomes available `ttlMs` after its last renewal. */
|
|
57
|
+
ttlMs: number;
|
|
58
|
+
/** Renewal interval (ms). The holder re-asserts the lease this often; must be `< ttlMs`. */
|
|
59
|
+
renewIntervalMs: number;
|
|
60
|
+
/** Boot-time wait window (ms) before {@link LeaseManager.acquire} throws. */
|
|
61
|
+
waitTimeoutMs: number;
|
|
62
|
+
/** Poll interval (ms) for the acquire wait loop. */
|
|
63
|
+
acquirePollIntervalMs?: number;
|
|
64
|
+
/**
|
|
65
|
+
* Delay primitive for the acquire poll loop. Defaults to a real `setTimeout`.
|
|
66
|
+
* Injected so tests drive the loop deterministically: a test `delay` advances
|
|
67
|
+
* the same injected clock by the poll interval and resolves immediately, so the
|
|
68
|
+
* wait deadline (read from `getNow`) trips without real waiting. Mirrors the
|
|
69
|
+
* `getNow` injection — not test-only scaffolding.
|
|
70
|
+
*/
|
|
71
|
+
delay?: (ms: number) => Promise<void>;
|
|
72
|
+
/**
|
|
73
|
+
* Called once when this holder loses the lease while running — either CAS-false
|
|
74
|
+
* on renewal (`'deposed'`: a successor stole it) or storage failures that make
|
|
75
|
+
* the holder unable to prove it still holds before the lease lapses
|
|
76
|
+
* (`'renewal-unconfirmable'`). In Step 1 the engine reacts by warning; Step 2
|
|
77
|
+
* uses this to halt fenced writes. The lease manager never throws into the
|
|
78
|
+
* renewal timer — it reports through this seam instead.
|
|
79
|
+
*/
|
|
80
|
+
onLeaseLost?: (reason: LeaseLostReason) => void;
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* A running lease manager.
|
|
84
|
+
*
|
|
85
|
+
* - `acquire()` blocks until this instance owns the lease, then resolves; throws
|
|
86
|
+
* {@link EngineLeaseAcquisitionTimeoutError} on timeout. Call before recovery.
|
|
87
|
+
* One exception to "resolved ⇒ owned": if the manager was `stop()`ped (disposal)
|
|
88
|
+
* while acquire was waiting, it resolves WITHOUT owning — the engine gates
|
|
89
|
+
* recovery on `disposed` so a stopped-then-resolved acquire never proceeds.
|
|
90
|
+
* - `startRenewal()` begins the heartbeat that keeps the lease held (drives
|
|
91
|
+
* {@link LeaseManager.renewOnce} on an interval).
|
|
92
|
+
* - `renewOnce()` runs a single renewal round; exposed for tests so renewal can be
|
|
93
|
+
* driven deterministically with an injected clock, mirroring the detector's
|
|
94
|
+
* `tick()`.
|
|
95
|
+
* - `currentEpochBytes()` returns the held epoch as bytes for Step-2 fencing
|
|
96
|
+
* conditions; `null` before a successful acquire. Synchronous and stable across
|
|
97
|
+
* renewals.
|
|
98
|
+
* - `release()` best-effort relinquishes the lease (holder key only) on dispose.
|
|
99
|
+
*/
|
|
100
|
+
export type LeaseManager = {
|
|
101
|
+
acquire(): Promise<void>;
|
|
102
|
+
startRenewal(): void;
|
|
103
|
+
renewOnce(): Promise<void>;
|
|
104
|
+
currentEpochBytes(): Uint8Array | null;
|
|
105
|
+
release(): Promise<void>;
|
|
106
|
+
stop(): void;
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* Create a lease manager. Does not start any timer or acquire anything itself —
|
|
110
|
+
* the engine drives `acquire()` at the boot gate (before recovery) and
|
|
111
|
+
* `startRenewal()` afterward, and clears the renewal timer through its own
|
|
112
|
+
* disposal path (mirroring how it owns the second-instance detector's interval).
|
|
113
|
+
*/
|
|
114
|
+
export declare function createLeaseManager(options: LeaseManagerOptions): LeaseManager;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { KEYS, storageConditionalBatch } from "../../storage/interface.js";
|
|
2
|
+
import {
|
|
3
|
+
decodeEpoch,
|
|
4
|
+
decodeHolder,
|
|
5
|
+
encodeEpoch,
|
|
6
|
+
encodeHolder
|
|
7
|
+
} from "./lease-codec.js";
|
|
8
|
+
import { EngineLeaseAcquisitionTimeoutError, EngineLeaseCorruptedError } from "./lease-errors.js";
|
|
9
|
+
const DEFAULT_ACQUIRE_POLL_INTERVAL_MS = 1000;
|
|
10
|
+
export function createLeaseManager(options) {
|
|
11
|
+
const { storage, holderId, getNow, ttlMs, renewIntervalMs, waitTimeoutMs } = options, acquirePollIntervalMs = options.acquirePollIntervalMs ?? DEFAULT_ACQUIRE_POLL_INTERVAL_MS, unconfirmableMarginMs = renewIntervalMs;
|
|
12
|
+
let stopped = !1, heldEpoch = null, heldEpochBytes = null, lastHolderBytes = null, renewalInterval = null, leaseLost = !1, inFlightRenewal = null;
|
|
13
|
+
const delay = options.delay ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
14
|
+
function reportLeaseLost(reason) {
|
|
15
|
+
if (leaseLost)
|
|
16
|
+
return;
|
|
17
|
+
leaseLost = !0;
|
|
18
|
+
options.onLeaseLost?.(reason);
|
|
19
|
+
}
|
|
20
|
+
async function readState() {
|
|
21
|
+
const holderRaw = await storage.get(KEYS.leaseHolder()), epochRaw = await storage.get(KEYS.leaseEpoch());
|
|
22
|
+
return {
|
|
23
|
+
epochRaw,
|
|
24
|
+
holderRaw,
|
|
25
|
+
epoch: epochRaw === null ? null : decodeEpoch(epochRaw),
|
|
26
|
+
holder: holderRaw === null ? null : decodeHolder(holderRaw)
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
async function takeOwnership(expectedEpochBytes, expectedHolderBytes, nextEpoch) {
|
|
30
|
+
const expiresAt = getNow() + ttlMs, holderBytes = encodeHolder({ holderId, expiresAt, epoch: nextEpoch }), committed = await storageConditionalBatch(storage, [
|
|
31
|
+
{ key: KEYS.leaseEpoch(), expectedValue: expectedEpochBytes },
|
|
32
|
+
{ key: KEYS.leaseHolder(), expectedValue: expectedHolderBytes }
|
|
33
|
+
], [
|
|
34
|
+
{ type: "put", key: KEYS.leaseEpoch(), value: encodeEpoch(nextEpoch) },
|
|
35
|
+
{ type: "put", key: KEYS.leaseHolder(), value: holderBytes }
|
|
36
|
+
]);
|
|
37
|
+
if (committed) {
|
|
38
|
+
heldEpoch = nextEpoch;
|
|
39
|
+
heldEpochBytes = encodeEpoch(nextEpoch);
|
|
40
|
+
lastHolderBytes = holderBytes;
|
|
41
|
+
}
|
|
42
|
+
return committed;
|
|
43
|
+
}
|
|
44
|
+
async function tryAcquireOnce() {
|
|
45
|
+
const { epochRaw, holderRaw, epoch, holder } = await readState();
|
|
46
|
+
if (epochRaw !== null && epoch === null)
|
|
47
|
+
throw new EngineLeaseCorruptedError('the "lease:epoch" high-water mark is present but does not decode to a valid epoch');
|
|
48
|
+
if (epochRaw === null && holderRaw !== null)
|
|
49
|
+
throw new EngineLeaseCorruptedError('a "lease:holder" record exists with no "lease:epoch" key (the lease protocol never deletes the epoch)');
|
|
50
|
+
if (holder !== null && getNow() < holder.expiresAt)
|
|
51
|
+
return !1;
|
|
52
|
+
const nextEpoch = (epoch ?? 0) + 1;
|
|
53
|
+
if (nextEpoch >= Number.MAX_SAFE_INTEGER)
|
|
54
|
+
throw new EngineLeaseCorruptedError(`the next ownership epoch (${nextEpoch}) is at or above the safe-integer ceiling and cannot be minted without bricking future boots`);
|
|
55
|
+
return takeOwnership(epochRaw, holderRaw, nextEpoch);
|
|
56
|
+
}
|
|
57
|
+
async function acquire() {
|
|
58
|
+
const startedAt = getNow(), deadline = startedAt + waitTimeoutMs;
|
|
59
|
+
let lastHolderId = null, firstAttempt = !0;
|
|
60
|
+
for (;; ) {
|
|
61
|
+
if (stopped)
|
|
62
|
+
return;
|
|
63
|
+
if (!firstAttempt && getNow() >= deadline)
|
|
64
|
+
throw new EngineLeaseAcquisitionTimeoutError(getNow() - startedAt, lastHolderId);
|
|
65
|
+
firstAttempt = !1;
|
|
66
|
+
if (await tryAcquireOnce())
|
|
67
|
+
return;
|
|
68
|
+
const holderRaw = await storage.get(KEYS.leaseHolder());
|
|
69
|
+
lastHolderId = holderRaw === null ? null : decodeHolder(holderRaw)?.holderId ?? null;
|
|
70
|
+
if (getNow() >= deadline)
|
|
71
|
+
throw new EngineLeaseAcquisitionTimeoutError(getNow() - startedAt, lastHolderId);
|
|
72
|
+
await delay(acquirePollIntervalMs);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
async function renewOnce() {
|
|
76
|
+
if (stopped || leaseLost || heldEpoch === null || lastHolderBytes === null)
|
|
77
|
+
return;
|
|
78
|
+
const expiresAt = getNow() + ttlMs, holderBytes = encodeHolder({ holderId, expiresAt, epoch: heldEpoch });
|
|
79
|
+
let committed;
|
|
80
|
+
try {
|
|
81
|
+
committed = await storageConditionalBatch(storage, [{ key: KEYS.leaseHolder(), expectedValue: lastHolderBytes }], [{ type: "put", key: KEYS.leaseHolder(), value: holderBytes }]);
|
|
82
|
+
} catch {
|
|
83
|
+
const priorExpiry = decodeHolder(lastHolderBytes)?.expiresAt ?? 0;
|
|
84
|
+
if (getNow() >= priorExpiry - unconfirmableMarginMs)
|
|
85
|
+
reportLeaseLost("renewal-unconfirmable");
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
if (committed) {
|
|
89
|
+
lastHolderBytes = holderBytes;
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
reportLeaseLost("deposed");
|
|
93
|
+
}
|
|
94
|
+
function renewUnderGuard() {
|
|
95
|
+
if (inFlightRenewal !== null)
|
|
96
|
+
return;
|
|
97
|
+
inFlightRenewal = renewOnce().catch(() => {}).finally(() => {
|
|
98
|
+
inFlightRenewal = null;
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
function startRenewal() {
|
|
102
|
+
if (stopped || renewalInterval !== null)
|
|
103
|
+
return;
|
|
104
|
+
renewalInterval = setInterval(() => {
|
|
105
|
+
renewUnderGuard();
|
|
106
|
+
}, renewIntervalMs);
|
|
107
|
+
renewalInterval.unref?.();
|
|
108
|
+
}
|
|
109
|
+
function currentEpochBytes() {
|
|
110
|
+
return heldEpochBytes === null ? null : heldEpochBytes.slice();
|
|
111
|
+
}
|
|
112
|
+
function clearRenewal() {
|
|
113
|
+
if (renewalInterval !== null) {
|
|
114
|
+
clearInterval(renewalInterval);
|
|
115
|
+
renewalInterval = null;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
async function release() {
|
|
119
|
+
stopped = !0;
|
|
120
|
+
clearRenewal();
|
|
121
|
+
if (inFlightRenewal !== null)
|
|
122
|
+
await inFlightRenewal;
|
|
123
|
+
if (lastHolderBytes === null)
|
|
124
|
+
return;
|
|
125
|
+
try {
|
|
126
|
+
if (await storageConditionalBatch(storage, [{ key: KEYS.leaseHolder(), expectedValue: lastHolderBytes }], [{ type: "delete", key: KEYS.leaseHolder() }]))
|
|
127
|
+
lastHolderBytes = null;
|
|
128
|
+
} catch {}
|
|
129
|
+
}
|
|
130
|
+
function stop() {
|
|
131
|
+
stopped = !0;
|
|
132
|
+
clearRenewal();
|
|
133
|
+
}
|
|
134
|
+
return { acquire, startRenewal, renewOnce, currentEpochBytes, release, stop };
|
|
135
|
+
}
|
|
@@ -1,15 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { encode } from "../../codec.js";
|
|
3
|
-
import {
|
|
4
|
-
VersionMismatchError,
|
|
5
|
-
buildVersionUpdateOperations,
|
|
6
|
-
checkVersionCompatibility,
|
|
7
|
-
migrateCheckpoint
|
|
8
|
-
} from "../../versioning.js";
|
|
1
|
+
import { VersionMismatchError, checkVersionCompatibility } from "../../versioning.js";
|
|
9
2
|
import {
|
|
10
3
|
diffWorkflowVersionTuples
|
|
11
4
|
} from "../../workflow-version-tuple.js";
|
|
12
|
-
import {
|
|
5
|
+
import { hydrateCheckpointReplayState } from "../checkpoint-replay.js";
|
|
13
6
|
export function createWorkflowVersionTuple(_internals, registration, _callbacks) {
|
|
14
7
|
return {
|
|
15
8
|
workflowVersion: registration.version
|
|
@@ -26,37 +19,22 @@ export function workflowStateWithVersionTuple(internals, state, versionTuple, _c
|
|
|
26
19
|
};
|
|
27
20
|
}
|
|
28
21
|
export function derivePreparedExecutionState(internals, workflowId, state, checkpoint, registration, callbacks) {
|
|
29
|
-
const compatibility = checkVersionCompatibility(checkpoint.version, registration.version
|
|
30
|
-
if (compatibility === "incompatible" || hasVersionTupleDrift
|
|
22
|
+
const compatibility = checkVersionCompatibility(checkpoint.version, registration.version), registeredVersionTuple = createWorkflowVersionTuple(internals, registration, callbacks), versionDiff = diffWorkflowVersionTuples(workflowVersionTupleFromState(internals, state, callbacks), registeredVersionTuple), hasVersionTupleDrift = versionDiff.workflowVersion !== void 0 || versionDiff.agentVersion !== void 0 || versionDiff.toolVersions !== void 0;
|
|
23
|
+
if (compatibility === "incompatible" || hasVersionTupleDrift)
|
|
31
24
|
throwVersionMismatch(internals, workflowId, state, registration, versionDiff, callbacks);
|
|
32
|
-
let preparedState = state, preparedCheckpoint = checkpoint, shouldPersistPreparedState = !1;
|
|
33
|
-
if ((compatibility === "needs-migration" || hasVersionTupleDrift) && registration.migrate) {
|
|
34
|
-
const migrated = migrateCheckpoint(checkpoint, checkpoint.version, registration.version, registration.migrate);
|
|
35
|
-
migrated.version = registeredVersionTuple.workflowVersion;
|
|
36
|
-
preparedCheckpoint = migrated;
|
|
37
|
-
preparedState = workflowStateWithVersionTuple(internals, state, registeredVersionTuple, callbacks);
|
|
38
|
-
shouldPersistPreparedState = !0;
|
|
39
|
-
}
|
|
40
25
|
return {
|
|
41
|
-
state
|
|
42
|
-
checkpoint
|
|
26
|
+
state,
|
|
27
|
+
checkpoint,
|
|
43
28
|
versionTuple: registeredVersionTuple,
|
|
44
|
-
shouldPersistPreparedState
|
|
29
|
+
shouldPersistPreparedState: !1
|
|
45
30
|
};
|
|
46
31
|
}
|
|
47
32
|
export async function prepareResumeState(internals, workflowId, state, checkpoint, checkpointBytes, registration, callbacks) {
|
|
48
|
-
const preparedExecutionState = derivePreparedExecutionState(internals, workflowId, state, checkpoint, registration, callbacks);
|
|
49
|
-
if (preparedExecutionState.shouldPersistPreparedState) {
|
|
50
|
-
const versionVisibilityOperations = buildWorkflowVisibilityIndexTransition(workflowId, state, preparedExecutionState.state).batchOps;
|
|
51
|
-
await internals.storage.batch([
|
|
52
|
-
...buildVersionUpdateOperations(workflowId, serializeCheckpoint(preparedExecutionState.checkpoint), preparedExecutionState.versionTuple.workflowVersion, encode(preparedExecutionState.state)),
|
|
53
|
-
...versionVisibilityOperations
|
|
54
|
-
]);
|
|
55
|
-
}
|
|
33
|
+
const preparedExecutionState = derivePreparedExecutionState(internals, workflowId, state, checkpoint, registration, callbacks), hydratedCheckpoint = await hydrateCheckpointReplayState(internals.storage, workflowId, preparedExecutionState.checkpoint);
|
|
56
34
|
return {
|
|
57
35
|
state: preparedExecutionState.state,
|
|
58
|
-
checkpoint:
|
|
59
|
-
serializedCheckpoint:
|
|
36
|
+
checkpoint: hydratedCheckpoint,
|
|
37
|
+
serializedCheckpoint: checkpointBytes,
|
|
60
38
|
versionTuple: preparedExecutionState.versionTuple
|
|
61
39
|
};
|
|
62
40
|
}
|
|
@@ -16,8 +16,8 @@ import type { EngineInternals } from '../internals.ts';
|
|
|
16
16
|
* has no marker and proceeds without touching the resolver — so a fail-closed
|
|
17
17
|
* resolver does not fail healthy no-services runs.
|
|
18
18
|
*
|
|
19
|
-
* Returns `false` to proceed (services available
|
|
20
|
-
*
|
|
19
|
+
* Returns `false` to proceed (services available or none expected). Returns
|
|
20
|
+
* `true` to STOP — the run was terminally
|
|
21
21
|
* failed (services unavailable), or the terminal commit faulted and the run was
|
|
22
22
|
* left for a later boot to retry. Either way the generator must not advance:
|
|
23
23
|
* driving it without services would crash the body and that throw would escape
|
|
@@ -36,10 +36,12 @@ import type { EngineInternals } from '../internals.ts';
|
|
|
36
36
|
* @param onCommitError - Records a fail-warn when `failRun` itself throws, so the
|
|
37
37
|
* swallowed terminal-commit fault is still observable.
|
|
38
38
|
*/
|
|
39
|
-
export declare function reprovideRecoveredServices(internals: EngineInternals, state: WorkflowState, failRun: (workflowId: string, error: Error) => Promise<void>, onCommitError: (source: string, error: unknown, workflowId: string) => void): Promise<boolean>;
|
|
39
|
+
export declare function reprovideRecoveredServices(internals: EngineInternals, state: WorkflowState, failRun: (workflowId: string, error: Error) => Promise<void>, onCommitError: (source: string, error: unknown, workflowId: string) => void, dispatchDiagnostic?: (event: Event) => void): Promise<boolean>;
|
|
40
40
|
/**
|
|
41
|
-
* The canonical terminal error for
|
|
42
|
-
*
|
|
43
|
-
* message (the failure category is `system`,
|
|
41
|
+
* The canonical terminal error for any run whose services could not be provided —
|
|
42
|
+
* both recovery re-provision paths and a scheduled-occurrence launch. Shared so
|
|
43
|
+
* every caller fails with an identical message (the failure category is `system`,
|
|
44
|
+
* the default for `failWorkflow`). The message is recovery-agnostic because a
|
|
45
|
+
* freshly launched scheduled occurrence has never been recovered.
|
|
44
46
|
*/
|
|
45
47
|
export declare function unavailableServicesError(workflowId: string, reason: string): Error;
|
|
@@ -1,12 +1,24 @@
|
|
|
1
1
|
import { KEYS } from "../../../storage/interface.js";
|
|
2
|
-
|
|
2
|
+
import { DevelopmentWarningEvent } from "../../events.js";
|
|
3
|
+
const RESOLVE_WORKFLOW_SERVICES_OPTION_PATH = "EngineOptions.resolveWorkflowServices";
|
|
4
|
+
export async function reprovideRecoveredServices(internals, state, failRun, onCommitError, dispatchDiagnostic = () => {}) {
|
|
3
5
|
const resolver = internals.options.resolveWorkflowServices;
|
|
4
|
-
if (internals.inlineStrategy === null
|
|
6
|
+
if (internals.inlineStrategy === null)
|
|
5
7
|
return !1;
|
|
6
8
|
if (internals.workflowServices.has(state.id))
|
|
7
9
|
return !1;
|
|
8
10
|
if (await internals.storage.get(KEYS.workflowHasServices(state.id)) === null)
|
|
9
11
|
return !1;
|
|
12
|
+
if (!resolver) {
|
|
13
|
+
const reason = missingServicesResolverReason(state.id);
|
|
14
|
+
dispatchDiagnostic(new DevelopmentWarningEvent(state.id, reason, [RESOLVE_WORKFLOW_SERVICES_OPTION_PATH]));
|
|
15
|
+
try {
|
|
16
|
+
await failRun(state.id, unavailableServicesError(state.id, reason));
|
|
17
|
+
} catch (error) {
|
|
18
|
+
onCommitError("reprovideRecoveredServices", error, state.id);
|
|
19
|
+
}
|
|
20
|
+
return !0;
|
|
21
|
+
}
|
|
10
22
|
let reason;
|
|
11
23
|
try {
|
|
12
24
|
const resolution = await resolver({
|
|
@@ -30,5 +42,8 @@ export async function reprovideRecoveredServices(internals, state, failRun, onCo
|
|
|
30
42
|
return !0;
|
|
31
43
|
}
|
|
32
44
|
export function unavailableServicesError(workflowId, reason) {
|
|
33
|
-
return Error(`
|
|
45
|
+
return Error(`Workflow "${workflowId}" services unavailable: ${reason}`);
|
|
46
|
+
}
|
|
47
|
+
function missingServicesResolverReason(workflowId) {
|
|
48
|
+
return `Workflow "${workflowId}" was started with services, but this engine has no resolveWorkflowServices option. Configure EngineOptions.resolveWorkflowServices before recovery so ctx.services can be re-provided.`;
|
|
34
49
|
}
|
|
@@ -7,6 +7,8 @@ import { WorkflowResumedEvent } from "../../events.js";
|
|
|
7
7
|
import { buildTimerBatchOperations } from "../../scheduler.js";
|
|
8
8
|
import { createCancelHandlerRegistration, resetCancelHandlers } from "../cancel-handlers.js";
|
|
9
9
|
import { rememberCommittedCheckpointBytes } from "../checkpoint-commit-snapshots.js";
|
|
10
|
+
import { rehydrateChildCancellationHandlers } from "../child-workflow-cancellation.js";
|
|
11
|
+
import { commitFencedEngineWrite } from "../fenced-write.js";
|
|
10
12
|
import { getWorkflowExecutionStartedAt } from "../handles.js";
|
|
11
13
|
import { loadWorkflowState } from "../storage-io.js";
|
|
12
14
|
import { getComposedWorkflowInterceptor } from "../strategy-helpers.js";
|
|
@@ -21,7 +23,7 @@ import {
|
|
|
21
23
|
setWorkflowStartHeaders
|
|
22
24
|
} from "./shared.js";
|
|
23
25
|
async function prepareRecoveredServicesOrFail(internals, state, callbacks) {
|
|
24
|
-
return reprovideRecoveredServices(internals, state, callbacks.failWorkflowForUnavailableServices, callbacks.handleCleanupError);
|
|
26
|
+
return reprovideRecoveredServices(internals, state, callbacks.failWorkflowForUnavailableServices, callbacks.handleCleanupError, callbacks.dispatchEvent);
|
|
25
27
|
}
|
|
26
28
|
function assertResumeNotTerminating(internals, workflowId) {
|
|
27
29
|
if (internals.terminalizingWorkflows.has(workflowId))
|
|
@@ -43,9 +45,10 @@ function commitSerializedResumeState(internals, args) {
|
|
|
43
45
|
setWorkflowStartHeaders(internals, workflowId, args.workflowStartHeaders, callbacks);
|
|
44
46
|
internals.parkedInlineWorkflows.delete(workflowId);
|
|
45
47
|
}
|
|
46
|
-
function relaunchInlineWorkflowAfterResume(internals, latestState, args) {
|
|
48
|
+
async function relaunchInlineWorkflowAfterResume(internals, latestState, args) {
|
|
47
49
|
const { workflowId, resumeCheckpoint, registration, callbacks } = args, accumulatedResults = new Map(resumeCheckpoint.accumulatedResults), workflowAbort = new AbortController;
|
|
48
50
|
resetCancelHandlers(internals, workflowId);
|
|
51
|
+
await rehydrateChildCancellationHandlers(internals, workflowId, callbacks);
|
|
49
52
|
const context = new Context({
|
|
50
53
|
workflowId,
|
|
51
54
|
workflowType: latestState.type,
|
|
@@ -65,7 +68,8 @@ function relaunchInlineWorkflowAfterResume(internals, latestState, args) {
|
|
|
65
68
|
...latestState.executionDeadline !== void 0 && {
|
|
66
69
|
deadline: latestState.executionDeadline
|
|
67
70
|
},
|
|
68
|
-
services: internals.workflowServices.get(workflowId)
|
|
71
|
+
services: internals.workflowServices.get(workflowId),
|
|
72
|
+
...internals.options.onLog != null && { logSink: internals.options.onLog }
|
|
69
73
|
});
|
|
70
74
|
setContextWorkflowInterceptor(context, getComposedWorkflowInterceptor(internals));
|
|
71
75
|
if (internals.options.development)
|
|
@@ -74,8 +78,11 @@ function relaunchInlineWorkflowAfterResume(internals, latestState, args) {
|
|
|
74
78
|
inlineStrategy.adoptWorkflow(workflowId, generator, context, workflowAbort);
|
|
75
79
|
inlineStrategy.continueWorkflow(workflowId, void 0);
|
|
76
80
|
}
|
|
77
|
-
function relaunchWorkerWorkflowAfterResume(internals, latestState, args) {
|
|
78
|
-
const { workflowId, resumeCheckpoint, workflowStartHeaders } = args
|
|
81
|
+
async function relaunchWorkerWorkflowAfterResume(internals, latestState, args) {
|
|
82
|
+
const { workflowId, resumeCheckpoint, workflowStartHeaders, callbacks } = args;
|
|
83
|
+
resetCancelHandlers(internals, workflowId);
|
|
84
|
+
await rehydrateChildCancellationHandlers(internals, workflowId, callbacks);
|
|
85
|
+
const serialized = serializeCheckpoint(resumeCheckpoint);
|
|
79
86
|
internals.strategy.startWorkflow({
|
|
80
87
|
workflowId,
|
|
81
88
|
workflowType: latestState.type,
|
|
@@ -103,10 +110,10 @@ async function performSerializedResume(internals, args) {
|
|
|
103
110
|
await reactivateSuspendedWorkflowState(internals, latestState);
|
|
104
111
|
commitSerializedResumeState(internals, args);
|
|
105
112
|
if (internals.inlineStrategy) {
|
|
106
|
-
relaunchInlineWorkflowAfterResume(internals, latestState, args);
|
|
113
|
+
await relaunchInlineWorkflowAfterResume(internals, latestState, args);
|
|
107
114
|
return;
|
|
108
115
|
}
|
|
109
|
-
relaunchWorkerWorkflowAfterResume(internals, latestState, args);
|
|
116
|
+
await relaunchWorkerWorkflowAfterResume(internals, latestState, args);
|
|
110
117
|
}
|
|
111
118
|
async function reactivateSuspendedWorkflowState(internals, state) {
|
|
112
119
|
if (state.status !== "suspended")
|
|
@@ -114,7 +121,7 @@ async function reactivateSuspendedWorkflowState(internals, state) {
|
|
|
114
121
|
const previousState = { ...state };
|
|
115
122
|
state.status = "running";
|
|
116
123
|
state.updatedAt = internals.options.getNow();
|
|
117
|
-
await internals
|
|
124
|
+
await commitFencedEngineWrite(internals, [
|
|
118
125
|
{ type: "put", key: KEYS.workflow(state.id), value: encode(state) },
|
|
119
126
|
...buildWorkflowVisibilityIndexTransition(state.id, previousState, state).batchOps,
|
|
120
127
|
...state.executionDeadline !== void 0 ? buildTimerBatchOperations({
|
|
@@ -123,7 +130,7 @@ async function reactivateSuspendedWorkflowState(internals, state) {
|
|
|
123
130
|
fireAt: state.executionDeadline,
|
|
124
131
|
kind: "execution-deadline"
|
|
125
132
|
}) : []
|
|
126
|
-
]);
|
|
133
|
+
], [], () => Error(`Resume of workflow "${state.id}" lost its CAS race.`));
|
|
127
134
|
}
|
|
128
135
|
export async function resumeWorkflowFromStorage(internals, workflowId, dispatchResumedEvent, callbacks) {
|
|
129
136
|
const stateBytes = await internals.storage.get(KEYS.workflow(workflowId));
|
|
@@ -22,7 +22,7 @@ export declare const EMPTY_STORAGE_VALUE: Uint8Array<ArrayBuffer>;
|
|
|
22
22
|
export type RecoverAllOptions = {
|
|
23
23
|
/**
|
|
24
24
|
* Skip stored running workflows whose type is not registered. Use only for
|
|
25
|
-
* rolling deploys or explicit storage
|
|
25
|
+
* rolling deploys or explicit operator storage repair.
|
|
26
26
|
*/
|
|
27
27
|
acknowledgeUnknownWorkflowTypes?: boolean;
|
|
28
28
|
};
|
|
@@ -56,6 +56,13 @@ export type LifecycleCallbacks = {
|
|
|
56
56
|
* `error` is the canonical {@link unavailableServicesError}.
|
|
57
57
|
*/
|
|
58
58
|
failWorkflowForUnavailableServices: (workflowId: string, error: Error) => Promise<void>;
|
|
59
|
+
/**
|
|
60
|
+
* Force a recovered workflow to a terminal `failed` state because its
|
|
61
|
+
* persisted checkpoint cannot be decoded on this runtime. The failure is
|
|
62
|
+
* isolated to the affected run so `recoverAll()` can continue recovering
|
|
63
|
+
* other workflows from the same storage backend.
|
|
64
|
+
*/
|
|
65
|
+
failWorkflowForCheckpointDecodeError: (workflowId: string, error: Error) => Promise<void>;
|
|
59
66
|
};
|
|
60
67
|
/**
|
|
61
68
|
* Pre-replay history circuit breaker. Called at every restore-from-checkpoint
|
|
@@ -2,6 +2,6 @@ import type { BatchOperation } from '../../../storage/interface.ts';
|
|
|
2
2
|
import type { Checkpoint, SearchAttributeValue, StartOptions, TimerEntry, WorkflowState } from '../../types.ts';
|
|
3
3
|
import type { EngineInternals } from '../internals.ts';
|
|
4
4
|
import { type LifecycleCallbacks, type RegistrationEntry } from './shared.ts';
|
|
5
|
-
export declare function buildStartBatchOperations(_internals: EngineInternals, workflowId: string, state: WorkflowState, checkpoint: Checkpoint, registration: RegistrationEntry, options: StartOptions | undefined, executionDeadline: number | undefined, delayedStartTimer: TimerEntry | undefined, workflowStartHeaders: Map<string, string> | undefined, additionalOperations: BatchOperation[] | undefined, callbacks: LifecycleCallbacks): BatchOperation[];
|
|
5
|
+
export declare function buildStartBatchOperations(_internals: EngineInternals, workflowId: string, state: WorkflowState, checkpoint: Checkpoint, registration: RegistrationEntry, options: StartOptions | undefined, executionDeadline: number | undefined, delayedStartTimer: TimerEntry | undefined, workflowStartHeaders: Map<string, string> | undefined, additionalOperations: BatchOperation[] | undefined, callbacks: LifecycleCallbacks, purgeDeleteOperations: BatchOperation[] | undefined): BatchOperation[];
|
|
6
6
|
export declare function buildInitialSearchAttributeOperations(_internals: EngineInternals, workflowId: string, registration: RegistrationEntry, searchAttributes: StartOptions['searchAttributes'], callbacks: LifecycleCallbacks): BatchOperation[];
|
|
7
7
|
export declare function validateSearchAttributes(_internals: EngineInternals, registration: RegistrationEntry, searchAttributes: Record<string, SearchAttributeValue>, _callbacks: LifecycleCallbacks): void;
|
|
@@ -8,8 +8,9 @@ import { validateAttributeValueSizes } from "../attributes-tags.js";
|
|
|
8
8
|
import { encodeWorkflowStartHeaders } from "../state-utilities.js";
|
|
9
9
|
import { buildWorkflowVisibilityIndexOperations } from "../workflow-indexes.js";
|
|
10
10
|
import { EMPTY_STORAGE_VALUE } from "./shared.js";
|
|
11
|
-
export function buildStartBatchOperations(_internals, workflowId, state, checkpoint, registration, options, executionDeadline, delayedStartTimer, workflowStartHeaders, additionalOperations, callbacks) {
|
|
11
|
+
export function buildStartBatchOperations(_internals, workflowId, state, checkpoint, registration, options, executionDeadline, delayedStartTimer, workflowStartHeaders, additionalOperations, callbacks, purgeDeleteOperations) {
|
|
12
12
|
const visibilityIndexOperations = buildWorkflowVisibilityIndexOperations(workflowId, null, state).batchOps, operations = [
|
|
13
|
+
...purgeDeleteOperations ?? [],
|
|
13
14
|
{ type: "put", key: KEYS.workflow(workflowId), value: encode(state) },
|
|
14
15
|
{
|
|
15
16
|
type: "put",
|