@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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { KEYS
|
|
1
|
+
import { KEYS } from "../../storage/interface.js";
|
|
2
2
|
import {
|
|
3
3
|
advanceCheckpoint,
|
|
4
4
|
deserializeCheckpoint,
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
validateCheckpointRoundTrip
|
|
7
7
|
} from "../checkpoint.js";
|
|
8
8
|
import { encode } from "../codec.js";
|
|
9
|
+
import { hasPendingAttributeChanges } from "../context/context-presence.js";
|
|
9
10
|
import { EMPTY_EVENT_HEAD, EventLog } from "../event-log.js";
|
|
10
11
|
import {
|
|
11
12
|
AttributesChangedEvent,
|
|
@@ -17,10 +18,22 @@ import {
|
|
|
17
18
|
getCommittedCheckpointBytes,
|
|
18
19
|
rememberCommittedCheckpointBytes
|
|
19
20
|
} from "./checkpoint-commit-snapshots.js";
|
|
21
|
+
import {
|
|
22
|
+
attachTransientCheckpointReplayPayload,
|
|
23
|
+
createCheckpointEventPayload,
|
|
24
|
+
mergeCheckpointReplayPayloads,
|
|
25
|
+
pruneCheckpointReplayState,
|
|
26
|
+
readCheckpointReplayPayload
|
|
27
|
+
} from "./checkpoint-replay.js";
|
|
28
|
+
import {
|
|
29
|
+
clearPendingAtomicWorkflowCommitSideEffects,
|
|
30
|
+
takePendingAtomicWorkflowCommitSideEffects
|
|
31
|
+
} from "./checkpoint-side-effects.js";
|
|
20
32
|
import {
|
|
21
33
|
appendCompactionOperations,
|
|
22
34
|
serializeDeletedEntries
|
|
23
35
|
} from "./event-log-compaction.js";
|
|
36
|
+
import { commitFencedEngineWrite } from "./fenced-write.js";
|
|
24
37
|
import { getTimelineInputSummary, getTimelineOperationLabel } from "./state-utilities.js";
|
|
25
38
|
import { buildPendingTimelineOperation } from "./termination.js";
|
|
26
39
|
import { notifyWorkflowFeedCommit } from "./workflow-feed.js";
|
|
@@ -57,21 +70,21 @@ async function persistInlineCheckpoint(internals, workflowId, operation, callbac
|
|
|
57
70
|
const current = internals.checkpoints.get(workflowId), context = internals.inlineStrategy?.getContext(workflowId);
|
|
58
71
|
if (!current || !context)
|
|
59
72
|
return;
|
|
60
|
-
const previousAttributes = { ...current.searchAttributes }, pendingAttributeChanges = context.checkpointPendingAttributeChanges,
|
|
73
|
+
const previousAttributes = { ...current.searchAttributes }, pendingAttributeChanges = context.checkpointPendingAttributeChanges, hasPendingAttributeChangesValue = hasPendingAttributeChanges(context), advanced = advanceCheckpoint(current, context.checkpointLocals, {
|
|
61
74
|
accumulatedResults: context.checkpointAccumulatedResults,
|
|
62
75
|
now: internals.options.getNow(),
|
|
63
76
|
...pendingAttributeChanges !== void 0 ? { searchAttributes: pendingAttributeChanges } : {}
|
|
64
|
-
}), commit = createCheckpointCommit(internals, workflowId,
|
|
65
|
-
appendAttributeOperations(workflowId, commit, previousAttributes, pendingAttributeChanges,
|
|
77
|
+
}), pruned = pruneCheckpointReplayState(advanced, resolvePendingOperationStep(operation, context.stepIndex)), commit = createCheckpointCommit(internals, workflowId, pruned.checkpoint, serializeCheckpoint(attachTransientCheckpointReplayPayload(pruned.checkpoint, pruned.replayPayload)), pruned.replayPayload);
|
|
78
|
+
appendAttributeOperations(workflowId, commit, previousAttributes, pendingAttributeChanges, hasPendingAttributeChangesValue, callbacks);
|
|
66
79
|
await commitCheckpoint(internals, workflowId, operation, commit, callbacks);
|
|
67
|
-
if (
|
|
80
|
+
if (hasPendingAttributeChangesValue)
|
|
68
81
|
callbacks.dispatchEvent(new AttributesChangedEvent(workflowId, { ...pendingAttributeChanges }));
|
|
69
82
|
}
|
|
70
83
|
async function persistWorkerCheckpoint(internals, workflowId, operation, workerCheckpointBytes, callbacks) {
|
|
71
|
-
const serialized = new Uint8Array(workerCheckpointBytes), checkpoint = deserializeCheckpoint(serialized);
|
|
72
|
-
await commitCheckpoint(internals, workflowId, operation, createCheckpointCommit(internals, workflowId, checkpoint,
|
|
84
|
+
const serialized = new Uint8Array(workerCheckpointBytes), checkpoint = deserializeCheckpoint(serialized), workerReplayPayload = readCheckpointReplayPayload(checkpoint), pruned = pruneCheckpointReplayState(checkpoint, resolvePendingOperationStep(operation, checkpoint.step)), replayPayload = mergeCheckpointReplayPayloads(workerReplayPayload, pruned.replayPayload), prunedSerialized = serializeCheckpoint(attachTransientCheckpointReplayPayload(pruned.checkpoint, replayPayload));
|
|
85
|
+
await commitCheckpoint(internals, workflowId, operation, createCheckpointCommit(internals, workflowId, pruned.checkpoint, prunedSerialized, replayPayload), callbacks);
|
|
73
86
|
}
|
|
74
|
-
function createCheckpointCommit(internals, workflowId, checkpoint, serialized) {
|
|
87
|
+
function createCheckpointCommit(internals, workflowId, checkpoint, serialized, replayPayload) {
|
|
75
88
|
const operations = [
|
|
76
89
|
{ type: "put", key: KEYS.checkpoint(workflowId), value: serialized }
|
|
77
90
|
];
|
|
@@ -85,14 +98,15 @@ function createCheckpointCommit(internals, workflowId, checkpoint, serialized) {
|
|
|
85
98
|
return {
|
|
86
99
|
checkpoint,
|
|
87
100
|
serialized,
|
|
101
|
+
...replayPayload === void 0 ? {} : { replayPayload },
|
|
88
102
|
...expectedSerialized !== void 0 ? { expectedSerialized } : {},
|
|
89
103
|
step: checkpoint.step,
|
|
90
104
|
timestamp: checkpoint.createdAt,
|
|
91
105
|
operations
|
|
92
106
|
};
|
|
93
107
|
}
|
|
94
|
-
function appendAttributeOperations(workflowId, commit, previousAttributes, pendingAttributeChanges,
|
|
95
|
-
if (!
|
|
108
|
+
function appendAttributeOperations(workflowId, commit, previousAttributes, pendingAttributeChanges, hasPendingAttributeChangesValue, callbacks) {
|
|
109
|
+
if (!hasPendingAttributeChangesValue)
|
|
96
110
|
return;
|
|
97
111
|
callbacks.validateAttributeValueSizes(pendingAttributeChanges ?? {});
|
|
98
112
|
commit.operations.push({
|
|
@@ -104,11 +118,15 @@ function appendAttributeOperations(workflowId, commit, previousAttributes, pendi
|
|
|
104
118
|
}
|
|
105
119
|
async function commitCheckpoint(internals, workflowId, operation, commit, callbacks) {
|
|
106
120
|
dispatchCheckpointSizeWarning(internals, workflowId, commit, callbacks);
|
|
107
|
-
const nextPendingTimelineEntry = callbacks.appendTimelineBatchOperations(workflowId, operation, commit.step, commit.timestamp, commit.operations), { newHead, timestamp } = appendCheckpointEventLog(internals, workflowId, commit), retentionWindow = internals.options.historyPolicy.retentionWindow, compaction = retentionWindow === null ? null : await appendCompactionOperations(internals.storage, workflowId, newHead.sequence, retentionWindow, commit.operations);
|
|
108
|
-
if (
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
121
|
+
const nextPendingTimelineEntry = callbacks.appendTimelineBatchOperations(workflowId, operation, commit.step, commit.timestamp, commit.operations), { newHead, timestamp } = appendCheckpointEventLog(internals, workflowId, commit), retentionWindow = internals.options.historyPolicy.retentionWindow, compaction = retentionWindow === null ? null : await appendCompactionOperations(internals.storage, workflowId, newHead.sequence, retentionWindow, commit.operations), pendingSideEffects = takePendingAtomicWorkflowCommitSideEffects(internals, workflowId);
|
|
122
|
+
if (pendingSideEffects !== void 0)
|
|
123
|
+
commit.operations.push(...pendingSideEffects.operations);
|
|
124
|
+
const storageSupportsConditionalBatch = internals.storage.capabilities().conditionalBatch, sideEffectConditions = checkpointSideEffectConditions(pendingSideEffects, storageSupportsConditionalBatch), conditions = buildCheckpointCommitConditions(workflowId, commit, storageSupportsConditionalBatch, sideEffectConditions);
|
|
125
|
+
await commitFencedEngineWrite(internals, commit.operations, conditions, () => {
|
|
126
|
+
return Error(`Checkpoint commit for workflow "${workflowId}" lost its CAS race against a newer checkpoint.`);
|
|
127
|
+
});
|
|
128
|
+
if (pendingSideEffects !== void 0)
|
|
129
|
+
clearPendingAtomicWorkflowCommitSideEffects(internals, workflowId);
|
|
112
130
|
if (commit.expectedSerialized !== void 0)
|
|
113
131
|
rememberCommittedCheckpointBytes(internals, workflowId, commit.serialized);
|
|
114
132
|
internals.pendingTimelineEntries.set(workflowId, nextPendingTimelineEntry);
|
|
@@ -128,15 +146,20 @@ async function commitCheckpoint(internals, workflowId, operation, commit, callba
|
|
|
128
146
|
if (historyEventLimitBreached(internals, newHead.sequence))
|
|
129
147
|
await callbacks.enforceHistoryCircuitBreaker(workflowId);
|
|
130
148
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
149
|
+
function checkpointSideEffectConditions(pendingSideEffects, storageSupportsConditionalBatch) {
|
|
150
|
+
if (!storageSupportsConditionalBatch)
|
|
151
|
+
return [];
|
|
152
|
+
return pendingSideEffects?.conditions ?? [];
|
|
153
|
+
}
|
|
154
|
+
function buildCheckpointCommitConditions(workflowId, commit, includeCheckpointCondition, sideEffectConditions) {
|
|
155
|
+
const conditions = [];
|
|
156
|
+
if (includeCheckpointCondition && commit.expectedSerialized !== void 0)
|
|
157
|
+
conditions.push({
|
|
134
158
|
key: KEYS.checkpoint(workflowId),
|
|
135
|
-
expectedValue: expectedSerialized
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
throw Error(`Checkpoint commit for workflow "${workflowId}" lost its CAS race against a newer checkpoint.`);
|
|
159
|
+
expectedValue: commit.expectedSerialized
|
|
160
|
+
});
|
|
161
|
+
conditions.push(...sideEffectConditions);
|
|
162
|
+
return conditions;
|
|
140
163
|
}
|
|
141
164
|
function historyEventLimitBreached(internals, sequence) {
|
|
142
165
|
const maxEvents = internals.options.historyPolicy.maxEvents;
|
|
@@ -154,7 +177,16 @@ function dispatchCheckpointSizeWarning(internals, workflowId, commit, callbacks)
|
|
|
154
177
|
callbacks.dispatchEvent(new CheckpointSizeWarningEvent(workflowId, commit.serialized.byteLength, commit.step));
|
|
155
178
|
}
|
|
156
179
|
function appendCheckpointEventLog(internals, workflowId, commit) {
|
|
157
|
-
return new EventLog(internals.storage, workflowId).appendToBatch({
|
|
180
|
+
return new EventLog(internals.storage, workflowId).appendToBatch({
|
|
181
|
+
type: "workflow:checkpoint",
|
|
182
|
+
payload: createCheckpointEventPayload(commit.step, commit.replayPayload)
|
|
183
|
+
}, commit.operations, internals.eventLogHeads.get(workflowId) ?? EMPTY_EVENT_HEAD, internals.workflowVersionTuples.get(workflowId));
|
|
184
|
+
}
|
|
185
|
+
function resolvePendingOperationStep(operation, fallbackStepIndex) {
|
|
186
|
+
const operationStep = "step" in operation ? operation.step : void 0;
|
|
187
|
+
if (typeof operationStep === "number" && Number.isSafeInteger(operationStep) && operationStep >= 0)
|
|
188
|
+
return operationStep;
|
|
189
|
+
return Math.max(0, fallbackStepIndex - 1);
|
|
158
190
|
}
|
|
159
191
|
export async function pruneCheckpointHistory(internals, workflowId, currentStep) {
|
|
160
192
|
const limit = internals.options.checkpointHistory;
|
|
@@ -175,7 +207,11 @@ export function validateDevelopmentCheckpoint(internals, workflowId, callbacks)
|
|
|
175
207
|
const step = context.stepIndex, current = internals.checkpoints.get(workflowId);
|
|
176
208
|
if (!current)
|
|
177
209
|
return;
|
|
178
|
-
const result = validateCheckpointRoundTrip(
|
|
210
|
+
const result = validateCheckpointRoundTrip({
|
|
211
|
+
...current,
|
|
212
|
+
locals: context.checkpointLocals,
|
|
213
|
+
accumulatedResults: context.checkpointAccumulatedResults
|
|
214
|
+
});
|
|
179
215
|
if (!result.valid) {
|
|
180
216
|
const fieldPaths = result.divergences.map((divergence) => divergence.path), message = `Checkpoint at step ${step} has ${result.divergences.length} non-serializable field(s)`;
|
|
181
217
|
callbacks.dispatchEvent(new DevelopmentWarningEvent(workflowId, message, fieldPaths));
|
|
@@ -3,6 +3,7 @@ import { deserializeCheckpoint } from "../checkpoint.js";
|
|
|
3
3
|
import { decode } from "../codec.js";
|
|
4
4
|
import { sanitizeDebugValueForDisplay } from "../debug-output.js";
|
|
5
5
|
import { EventLog } from "../event-log.js";
|
|
6
|
+
import { hydrateCheckpointReplayState } from "./checkpoint-replay.js";
|
|
6
7
|
import { readEventLogWatermark } from "./event-log-compaction.js";
|
|
7
8
|
import {
|
|
8
9
|
sanitizeCheckpointState,
|
|
@@ -41,7 +42,7 @@ export async function getCheckpointAt(internals, workflowId, step) {
|
|
|
41
42
|
const bytes = await internals.storage.get(KEYS.checkpointHistory(workflowId, step));
|
|
42
43
|
if (!bytes)
|
|
43
44
|
return null;
|
|
44
|
-
const checkpoint = deserializeCheckpoint(bytes);
|
|
45
|
+
const checkpoint = await hydrateCheckpointReplayState(internals.storage, workflowId, deserializeCheckpoint(bytes));
|
|
45
46
|
return sanitizeCheckpointState({
|
|
46
47
|
step: checkpoint.step,
|
|
47
48
|
locals: checkpoint.locals,
|
|
@@ -75,7 +76,7 @@ export async function replayTo(internals, workflowId, step) {
|
|
|
75
76
|
const bytes = await internals.storage.get(KEYS.checkpointHistory(workflowId, step));
|
|
76
77
|
if (!bytes)
|
|
77
78
|
return null;
|
|
78
|
-
const
|
|
79
|
+
const entries = await new EventLog(internals.storage, workflowId).replay(Math.max(step - 1, -1)), checkpoint = await hydrateCheckpointReplayState(internals.storage, workflowId, deserializeCheckpoint(bytes)), watermark = await readEventLogWatermark(internals.storage, workflowId);
|
|
79
80
|
return {
|
|
80
81
|
checkpoint: sanitizeCheckpointState({
|
|
81
82
|
step: checkpoint.step,
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type Storage } from '../../storage/interface.ts';
|
|
2
|
+
import type { Checkpoint, WorkerReplayOperationFailure, WorkerReplayOperationSignature } from '../types.ts';
|
|
3
|
+
export declare const CHECKPOINT_REPLAY_PAYLOAD_KEY = "__weftCheckpointReplay";
|
|
4
|
+
export type CheckpointReplayPayload = {
|
|
5
|
+
accumulatedResults?: Array<[number, unknown]>;
|
|
6
|
+
workerReplaySignatures?: Array<[number, WorkerReplayOperationSignature]>;
|
|
7
|
+
workerReplayFailures?: Array<[number, WorkerReplayOperationFailure]>;
|
|
8
|
+
};
|
|
9
|
+
export type PrunedCheckpointReplayState = {
|
|
10
|
+
checkpoint: Checkpoint;
|
|
11
|
+
replayPayload: CheckpointReplayPayload | undefined;
|
|
12
|
+
};
|
|
13
|
+
export declare function pruneCheckpointReplayState(checkpoint: Checkpoint, pendingOperationStep: number): PrunedCheckpointReplayState;
|
|
14
|
+
export declare function hydrateCheckpointReplayState(storage: Storage, workflowId: string, checkpoint: Checkpoint): Promise<Checkpoint>;
|
|
15
|
+
export declare function hydrateCheckpointReplayStateFromPayload(checkpoint: Checkpoint, replayPayload: CheckpointReplayPayload | undefined): Checkpoint;
|
|
16
|
+
export declare function attachTransientCheckpointReplayPayload(checkpoint: Checkpoint, replayPayload: CheckpointReplayPayload | undefined): Checkpoint;
|
|
17
|
+
export declare function createCheckpointEventPayload(checkpointStep: number, replayPayload: CheckpointReplayPayload | undefined): Record<string, unknown>;
|
|
18
|
+
export declare function mergeCheckpointReplayPayloads(left: CheckpointReplayPayload | undefined, right: CheckpointReplayPayload | undefined): CheckpointReplayPayload | undefined;
|
|
19
|
+
export declare function readCheckpointReplayPayload(payload: unknown): CheckpointReplayPayload | undefined;
|
|
20
|
+
export declare function stripInternalCheckpointReplayPayload(payload: Record<string, unknown>): Record<string, unknown>;
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { KEYS } from "../../storage/interface.js";
|
|
2
|
+
import { decode } from "../codec.js";
|
|
3
|
+
import { isWorkflowLogEntry } from "../event-log-shared.js";
|
|
4
|
+
import { WORKER_REPLAY_SIGNATURE_FORMAT } from "../types/checkpoint.js";
|
|
5
|
+
export const CHECKPOINT_REPLAY_PAYLOAD_KEY = "__weftCheckpointReplay";
|
|
6
|
+
const NO_REPLAY_WATERMARK = -1;
|
|
7
|
+
export function pruneCheckpointReplayState(checkpoint, pendingOperationStep) {
|
|
8
|
+
const checkpointWithoutReplayPayload = stripTransientCheckpointReplayPayload(checkpoint), previousWatermark = checkpointWithoutReplayPayload.accumulatedResultReplayWatermark ?? NO_REPLAY_WATERMARK, consumedResults = entriesBeforeStep(checkpointWithoutReplayPayload.accumulatedResults, pendingOperationStep), consumedSignatures = entriesBeforeStep(checkpointWithoutReplayPayload.workerReplaySignatures ?? [], pendingOperationStep), consumedFailures = entriesBeforeStep(checkpointWithoutReplayPayload.workerReplayFailures ?? [], pendingOperationStep), replayPayload = buildReplayPayload({
|
|
9
|
+
accumulatedResults: entriesAfterWatermark(consumedResults, previousWatermark),
|
|
10
|
+
workerReplaySignatures: entriesAfterWatermark(consumedSignatures, previousWatermark),
|
|
11
|
+
workerReplayFailures: entriesAfterWatermark(consumedFailures, previousWatermark)
|
|
12
|
+
}), nextWatermark = resolveNextReplayWatermark(previousWatermark, replayPayload), retainedWorkerReplaySignatures = entriesAtOrAfterStep(checkpointWithoutReplayPayload.workerReplaySignatures ?? [], pendingOperationStep), retainedWorkerReplayFailures = entriesAtOrAfterStep(checkpointWithoutReplayPayload.workerReplayFailures ?? [], pendingOperationStep), prunedCheckpoint = {
|
|
13
|
+
...checkpointWithoutReplayPayload,
|
|
14
|
+
accumulatedResults: entriesAtOrAfterStep(checkpointWithoutReplayPayload.accumulatedResults, pendingOperationStep),
|
|
15
|
+
...nextWatermark === NO_REPLAY_WATERMARK ? {} : { accumulatedResultReplayWatermark: nextWatermark },
|
|
16
|
+
...optionalEntries("workerReplaySignatures", retainedWorkerReplaySignatures),
|
|
17
|
+
...optionalEntries("workerReplayFailures", retainedWorkerReplayFailures)
|
|
18
|
+
};
|
|
19
|
+
if (nextWatermark === NO_REPLAY_WATERMARK)
|
|
20
|
+
delete prunedCheckpoint.accumulatedResultReplayWatermark;
|
|
21
|
+
if (retainedWorkerReplaySignatures.length === 0)
|
|
22
|
+
delete prunedCheckpoint.workerReplaySignatures;
|
|
23
|
+
if (retainedWorkerReplayFailures.length === 0)
|
|
24
|
+
delete prunedCheckpoint.workerReplayFailures;
|
|
25
|
+
return {
|
|
26
|
+
checkpoint: prunedCheckpoint,
|
|
27
|
+
replayPayload
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export async function hydrateCheckpointReplayState(storage, workflowId, checkpoint) {
|
|
31
|
+
const replayPayloads = [], checkpointReplayPayload = readCheckpointReplayPayload(checkpoint);
|
|
32
|
+
if (checkpointReplayPayload !== void 0)
|
|
33
|
+
replayPayloads.push(checkpointReplayPayload);
|
|
34
|
+
const compactedReplayPayload = await readCompactedCheckpointReplayPayload(storage, workflowId);
|
|
35
|
+
if (compactedReplayPayload !== void 0)
|
|
36
|
+
replayPayloads.push(compactedReplayPayload);
|
|
37
|
+
for await (const [, entryBytes] of storage.scan(KEYS.eventPrefix(workflowId))) {
|
|
38
|
+
const decoded = decode(entryBytes);
|
|
39
|
+
if (!isWorkflowLogEntry(decoded))
|
|
40
|
+
continue;
|
|
41
|
+
const entry = decoded, checkpointStep = getCheckpointEventStep(entry.payload);
|
|
42
|
+
if (checkpointStep === void 0)
|
|
43
|
+
continue;
|
|
44
|
+
if (checkpointStep > checkpoint.step)
|
|
45
|
+
break;
|
|
46
|
+
const replayPayload = readCheckpointReplayPayload(entry.payload);
|
|
47
|
+
if (replayPayload === void 0)
|
|
48
|
+
continue;
|
|
49
|
+
replayPayloads.push(replayPayload);
|
|
50
|
+
}
|
|
51
|
+
return hydrateCheckpointReplayStateFromPayloads(stripTransientCheckpointReplayPayload(checkpoint), replayPayloads);
|
|
52
|
+
}
|
|
53
|
+
export function hydrateCheckpointReplayStateFromPayload(checkpoint, replayPayload) {
|
|
54
|
+
return hydrateCheckpointReplayStateFromPayloads(stripTransientCheckpointReplayPayload(checkpoint), replayPayload === void 0 ? [] : [replayPayload]);
|
|
55
|
+
}
|
|
56
|
+
function hydrateCheckpointReplayStateFromPayloads(checkpoint, replayPayloads) {
|
|
57
|
+
const accumulatedResults = new Map, workerReplaySignatures = new Map, workerReplayFailures = new Map;
|
|
58
|
+
for (const replayPayload of replayPayloads)
|
|
59
|
+
mergeReplayPayload({
|
|
60
|
+
accumulatedResults,
|
|
61
|
+
workerReplaySignatures,
|
|
62
|
+
workerReplayFailures
|
|
63
|
+
}, replayPayload);
|
|
64
|
+
mergeEntries(accumulatedResults, checkpoint.accumulatedResults);
|
|
65
|
+
mergeEntries(workerReplaySignatures, checkpoint.workerReplaySignatures ?? []);
|
|
66
|
+
mergeEntries(workerReplayFailures, checkpoint.workerReplayFailures ?? []);
|
|
67
|
+
return {
|
|
68
|
+
...checkpoint,
|
|
69
|
+
accumulatedResults: sortedEntries(accumulatedResults),
|
|
70
|
+
...optionalEntries("workerReplaySignatures", sortedEntries(workerReplaySignatures)),
|
|
71
|
+
...optionalEntries("workerReplayFailures", sortedEntries(workerReplayFailures))
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
export function attachTransientCheckpointReplayPayload(checkpoint, replayPayload) {
|
|
75
|
+
if (replayPayload === void 0)
|
|
76
|
+
return checkpoint;
|
|
77
|
+
return {
|
|
78
|
+
...checkpoint,
|
|
79
|
+
[CHECKPOINT_REPLAY_PAYLOAD_KEY]: replayPayload
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
export function createCheckpointEventPayload(checkpointStep, replayPayload) {
|
|
83
|
+
return replayPayload === void 0 ? { step: checkpointStep } : { step: checkpointStep, [CHECKPOINT_REPLAY_PAYLOAD_KEY]: replayPayload };
|
|
84
|
+
}
|
|
85
|
+
export function mergeCheckpointReplayPayloads(left, right) {
|
|
86
|
+
if (left === void 0)
|
|
87
|
+
return right;
|
|
88
|
+
if (right === void 0)
|
|
89
|
+
return left;
|
|
90
|
+
return buildReplayPayload({
|
|
91
|
+
accumulatedResults: [...left.accumulatedResults ?? [], ...right.accumulatedResults ?? []],
|
|
92
|
+
workerReplaySignatures: [
|
|
93
|
+
...left.workerReplaySignatures ?? [],
|
|
94
|
+
...right.workerReplaySignatures ?? []
|
|
95
|
+
],
|
|
96
|
+
workerReplayFailures: [
|
|
97
|
+
...left.workerReplayFailures ?? [],
|
|
98
|
+
...right.workerReplayFailures ?? []
|
|
99
|
+
]
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
export function readCheckpointReplayPayload(payload) {
|
|
103
|
+
if (!isRecord(payload))
|
|
104
|
+
return;
|
|
105
|
+
const replayPayload = payload[CHECKPOINT_REPLAY_PAYLOAD_KEY];
|
|
106
|
+
if (!isRecord(replayPayload))
|
|
107
|
+
return;
|
|
108
|
+
return readCheckpointReplayPayloadRecord(replayPayload);
|
|
109
|
+
}
|
|
110
|
+
export function stripInternalCheckpointReplayPayload(payload) {
|
|
111
|
+
const { [CHECKPOINT_REPLAY_PAYLOAD_KEY]: _internalReplayPayload, ...publicPayload } = payload;
|
|
112
|
+
return publicPayload;
|
|
113
|
+
}
|
|
114
|
+
function buildReplayPayload(payload) {
|
|
115
|
+
const replayPayload = {}, accumulatedResults = payload.accumulatedResults, workerReplaySignatures = payload.workerReplaySignatures, workerReplayFailures = payload.workerReplayFailures;
|
|
116
|
+
if (accumulatedResults !== void 0 && accumulatedResults.length > 0)
|
|
117
|
+
replayPayload.accumulatedResults = accumulatedResults;
|
|
118
|
+
if (workerReplaySignatures !== void 0 && workerReplaySignatures.length > 0)
|
|
119
|
+
replayPayload.workerReplaySignatures = workerReplaySignatures;
|
|
120
|
+
if (workerReplayFailures !== void 0 && workerReplayFailures.length > 0)
|
|
121
|
+
replayPayload.workerReplayFailures = workerReplayFailures;
|
|
122
|
+
return Object.keys(replayPayload).length === 0 ? void 0 : replayPayload;
|
|
123
|
+
}
|
|
124
|
+
function resolveNextReplayWatermark(previousWatermark, replayPayload) {
|
|
125
|
+
if (replayPayload === void 0)
|
|
126
|
+
return previousWatermark;
|
|
127
|
+
let nextWatermark = previousWatermark;
|
|
128
|
+
for (const entries of [
|
|
129
|
+
replayPayload.accumulatedResults ?? [],
|
|
130
|
+
replayPayload.workerReplaySignatures ?? [],
|
|
131
|
+
replayPayload.workerReplayFailures ?? []
|
|
132
|
+
])
|
|
133
|
+
for (const [step] of entries)
|
|
134
|
+
nextWatermark = Math.max(nextWatermark, step);
|
|
135
|
+
return nextWatermark;
|
|
136
|
+
}
|
|
137
|
+
function entriesBeforeStep(entries, step) {
|
|
138
|
+
return entries.filter(([entryStep]) => entryStep < step);
|
|
139
|
+
}
|
|
140
|
+
function entriesAtOrAfterStep(entries, step) {
|
|
141
|
+
return entries.filter(([entryStep]) => entryStep >= step);
|
|
142
|
+
}
|
|
143
|
+
function entriesAfterWatermark(entries, watermark) {
|
|
144
|
+
return entries.filter(([entryStep]) => entryStep > watermark);
|
|
145
|
+
}
|
|
146
|
+
function optionalEntries(key, entries) {
|
|
147
|
+
return entries.length === 0 ? {} : { [key]: entries };
|
|
148
|
+
}
|
|
149
|
+
function stripTransientCheckpointReplayPayload(checkpoint) {
|
|
150
|
+
const checkpointWithReplayPayload = checkpoint, { [CHECKPOINT_REPLAY_PAYLOAD_KEY]: _replayPayload, ...checkpointWithoutReplayPayload } = checkpointWithReplayPayload;
|
|
151
|
+
return checkpointWithoutReplayPayload;
|
|
152
|
+
}
|
|
153
|
+
function sortedEntries(entries) {
|
|
154
|
+
return [...entries.entries()].toSorted(([leftStep], [rightStep]) => leftStep - rightStep);
|
|
155
|
+
}
|
|
156
|
+
function mergeEntries(target, entries) {
|
|
157
|
+
for (const [step, value] of entries)
|
|
158
|
+
target.set(step, value);
|
|
159
|
+
}
|
|
160
|
+
function mergeReplayPayload(target, replayPayload) {
|
|
161
|
+
mergeEntries(target.accumulatedResults, replayPayload.accumulatedResults ?? []);
|
|
162
|
+
mergeEntries(target.workerReplaySignatures, replayPayload.workerReplaySignatures ?? []);
|
|
163
|
+
mergeEntries(target.workerReplayFailures, replayPayload.workerReplayFailures ?? []);
|
|
164
|
+
}
|
|
165
|
+
function getCheckpointEventStep(payload) {
|
|
166
|
+
if (!isRecord(payload))
|
|
167
|
+
return;
|
|
168
|
+
const step = payload.step;
|
|
169
|
+
return typeof step === "number" && Number.isSafeInteger(step) && step >= 0 ? step : void 0;
|
|
170
|
+
}
|
|
171
|
+
function readCheckpointReplayPayloadRecord(replayPayload) {
|
|
172
|
+
const accumulatedResults = readUnknownEntries(replayPayload.accumulatedResults), workerReplaySignatures = readWorkerReplaySignatureEntries(replayPayload.workerReplaySignatures), workerReplayFailures = readWorkerReplayFailureEntries(replayPayload.workerReplayFailures);
|
|
173
|
+
return buildReplayPayload({
|
|
174
|
+
...accumulatedResults === void 0 ? {} : { accumulatedResults },
|
|
175
|
+
...workerReplaySignatures === void 0 ? {} : { workerReplaySignatures },
|
|
176
|
+
...workerReplayFailures === void 0 ? {} : { workerReplayFailures }
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
async function readCompactedCheckpointReplayPayload(storage, workflowId) {
|
|
180
|
+
const watermarkBytes = await storage.get(KEYS.eventWatermark(workflowId));
|
|
181
|
+
if (watermarkBytes === null)
|
|
182
|
+
return;
|
|
183
|
+
const watermark = decode(watermarkBytes);
|
|
184
|
+
if (!isRecord(watermark))
|
|
185
|
+
return;
|
|
186
|
+
const replayPayload = watermark.checkpointReplay;
|
|
187
|
+
return isRecord(replayPayload) ? readCheckpointReplayPayloadRecord(replayPayload) : void 0;
|
|
188
|
+
}
|
|
189
|
+
function readUnknownEntries(value) {
|
|
190
|
+
if (!Array.isArray(value))
|
|
191
|
+
return;
|
|
192
|
+
const entries = [];
|
|
193
|
+
for (const entry of value) {
|
|
194
|
+
if (!Array.isArray(entry) || entry.length !== 2 || !isReplayStep(entry[0]))
|
|
195
|
+
continue;
|
|
196
|
+
entries.push([entry[0], entry[1]]);
|
|
197
|
+
}
|
|
198
|
+
return entries;
|
|
199
|
+
}
|
|
200
|
+
function readWorkerReplaySignatureEntries(value) {
|
|
201
|
+
if (!Array.isArray(value))
|
|
202
|
+
return;
|
|
203
|
+
const entries = [];
|
|
204
|
+
for (const entry of value) {
|
|
205
|
+
if (!Array.isArray(entry) || entry.length !== 2 || !isReplayStep(entry[0]))
|
|
206
|
+
continue;
|
|
207
|
+
if (!isWorkerReplaySignature(entry[1]))
|
|
208
|
+
continue;
|
|
209
|
+
entries.push([entry[0], entry[1]]);
|
|
210
|
+
}
|
|
211
|
+
return entries;
|
|
212
|
+
}
|
|
213
|
+
function readWorkerReplayFailureEntries(value) {
|
|
214
|
+
if (!Array.isArray(value))
|
|
215
|
+
return;
|
|
216
|
+
const entries = [];
|
|
217
|
+
for (const entry of value) {
|
|
218
|
+
if (!Array.isArray(entry) || entry.length !== 2 || !isReplayStep(entry[0]))
|
|
219
|
+
continue;
|
|
220
|
+
if (!isWorkerReplayFailure(entry[1]))
|
|
221
|
+
continue;
|
|
222
|
+
entries.push([entry[0], entry[1]]);
|
|
223
|
+
}
|
|
224
|
+
return entries;
|
|
225
|
+
}
|
|
226
|
+
function isRecord(value) {
|
|
227
|
+
return typeof value === "object" && value !== null;
|
|
228
|
+
}
|
|
229
|
+
function isReplayStep(value) {
|
|
230
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
231
|
+
}
|
|
232
|
+
function isWorkerReplaySignature(value) {
|
|
233
|
+
if (!isRecord(value))
|
|
234
|
+
return !1;
|
|
235
|
+
return value.format === WORKER_REPLAY_SIGNATURE_FORMAT && typeof value.operationType === "string" && typeof value.stableFieldsDigest === "string" && isReplayStep(value.stableFieldsByteLength);
|
|
236
|
+
}
|
|
237
|
+
function isWorkerReplayFailure(value) {
|
|
238
|
+
if (!isRecord(value))
|
|
239
|
+
return !1;
|
|
240
|
+
const failureCategory = value.failureCategory;
|
|
241
|
+
return value.status === "failed" && typeof value.error === "string" && (value.errorName === void 0 || typeof value.errorName === "string") && (failureCategory === void 0 || failureCategory === "application" || failureCategory === "cancellation" || failureCategory === "resource" || failureCategory === "system" || failureCategory === "timeout");
|
|
242
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { BatchOperation, ConditionalBatchCondition } from '../../storage/interface.ts';
|
|
2
|
+
import type { EngineInternals } from './internals.ts';
|
|
3
|
+
export type AtomicWorkflowCommitSideEffects = {
|
|
4
|
+
conditions: ConditionalBatchCondition[];
|
|
5
|
+
operations: BatchOperation[];
|
|
6
|
+
};
|
|
7
|
+
export declare function stageAtomicWorkflowCommitSideEffects(internals: EngineInternals, workflowId: string, sideEffects: AtomicWorkflowCommitSideEffects): void;
|
|
8
|
+
export declare function takePendingAtomicWorkflowCommitSideEffects(internals: EngineInternals, workflowId: string): AtomicWorkflowCommitSideEffects | undefined;
|
|
9
|
+
export declare function clearPendingAtomicWorkflowCommitSideEffects(internals: EngineInternals, workflowId: string): void;
|
|
10
|
+
/**
|
|
11
|
+
* Non-destructively report whether a workflow's pending atomic side-effect buffer
|
|
12
|
+
* already stages a `put` to `key`. Unlike {@link takePendingAtomicWorkflowCommitSideEffects},
|
|
13
|
+
* this does NOT consume the buffer, so it is safe to call at a gate that runs before the
|
|
14
|
+
* commit that will flush those same side-effects.
|
|
15
|
+
*
|
|
16
|
+
* The terminal-transition path (#446) needs this: `ctx.setFinalizerState()` stages the
|
|
17
|
+
* `wf-finalizer-state:` put as a pending side-effect that the terminal batch flushes, but
|
|
18
|
+
* a pre-batch `storage.get()` cannot see a staged-but-unflushed write. Peeking the buffer
|
|
19
|
+
* lets the terminal batch stage its teardown marker atomically alongside that put — without
|
|
20
|
+
* it, a `setFinalizerState` with no intervening checkpoint would commit the resource state
|
|
21
|
+
* yet skip the teardown marker, silently leaking the external resource.
|
|
22
|
+
*/
|
|
23
|
+
export declare function pendingAtomicWorkflowCommitSideEffectsStagePut(internals: EngineInternals, workflowId: string, key: string): boolean;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export function stageAtomicWorkflowCommitSideEffects(internals, workflowId, sideEffects) {
|
|
2
|
+
if (sideEffects.conditions.length === 0 && sideEffects.operations.length === 0)
|
|
3
|
+
return;
|
|
4
|
+
const pending = internals.pendingAtomicWorkflowCommitSideEffects.get(workflowId);
|
|
5
|
+
if (pending === void 0) {
|
|
6
|
+
internals.pendingAtomicWorkflowCommitSideEffects.set(workflowId, {
|
|
7
|
+
conditions: [...sideEffects.conditions],
|
|
8
|
+
operations: [...sideEffects.operations]
|
|
9
|
+
});
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
pending.conditions.push(...sideEffects.conditions);
|
|
13
|
+
pending.operations.push(...sideEffects.operations);
|
|
14
|
+
}
|
|
15
|
+
export function takePendingAtomicWorkflowCommitSideEffects(internals, workflowId) {
|
|
16
|
+
const pending = internals.pendingAtomicWorkflowCommitSideEffects.get(workflowId);
|
|
17
|
+
if (pending === void 0)
|
|
18
|
+
return;
|
|
19
|
+
internals.pendingAtomicWorkflowCommitSideEffects.delete(workflowId);
|
|
20
|
+
if (pending.conditions.length === 0 && pending.operations.length === 0)
|
|
21
|
+
return;
|
|
22
|
+
return {
|
|
23
|
+
conditions: [...pending.conditions],
|
|
24
|
+
operations: [...pending.operations]
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export function clearPendingAtomicWorkflowCommitSideEffects(internals, workflowId) {
|
|
28
|
+
internals.pendingAtomicWorkflowCommitSideEffects.delete(workflowId);
|
|
29
|
+
}
|
|
30
|
+
export function pendingAtomicWorkflowCommitSideEffectsStagePut(internals, workflowId, key) {
|
|
31
|
+
const pending = internals.pendingAtomicWorkflowCommitSideEffects.get(workflowId);
|
|
32
|
+
if (pending === void 0)
|
|
33
|
+
return !1;
|
|
34
|
+
return pending.operations.some((operation) => operation.type === "put" && operation.key === key);
|
|
35
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type BatchOperation } from '../../storage/interface.ts';
|
|
2
|
+
import type { WorkflowHandle } from './handles.ts';
|
|
3
|
+
import type { EngineInternals } from './internals.ts';
|
|
4
|
+
type ChildCancellationCallbacks = {
|
|
5
|
+
getHandle: (workflowId: string) => WorkflowHandle;
|
|
6
|
+
};
|
|
7
|
+
export declare function buildChildCancellationOperations(internals: EngineInternals, workflowId: string, childWorkflowId: string): BatchOperation[];
|
|
8
|
+
export declare function registerChildCancellationHandler(internals: EngineInternals, workflowId: string, childWorkflowId: string, callbacks: ChildCancellationCallbacks): void;
|
|
9
|
+
export declare function rehydrateChildCancellationHandlers(internals: EngineInternals, workflowId: string, callbacks: ChildCancellationCallbacks): Promise<void>;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { KEYS, decodeStorageKeyComponent } from "../../storage/interface.js";
|
|
2
|
+
import { registerCancelHandler } from "./cancel-handlers.js";
|
|
3
|
+
import { EMPTY_STORAGE_VALUE } from "./lifecycle/shared.js";
|
|
4
|
+
export function buildChildCancellationOperations(internals, workflowId, childWorkflowId) {
|
|
5
|
+
const operations = [
|
|
6
|
+
{
|
|
7
|
+
type: "put",
|
|
8
|
+
key: KEYS.childCancellation(workflowId, childWorkflowId),
|
|
9
|
+
value: EMPTY_STORAGE_VALUE
|
|
10
|
+
}
|
|
11
|
+
], needsCleanupMarker = !internals.workflowsNeedingTerminalCleanup.has(workflowId);
|
|
12
|
+
internals.workflowsNeedingTerminalCleanup.add(workflowId);
|
|
13
|
+
if (needsCleanupMarker)
|
|
14
|
+
operations.push({
|
|
15
|
+
type: "put",
|
|
16
|
+
key: KEYS.terminalCleanupNeeded(workflowId),
|
|
17
|
+
value: EMPTY_STORAGE_VALUE
|
|
18
|
+
});
|
|
19
|
+
return operations;
|
|
20
|
+
}
|
|
21
|
+
export function registerChildCancellationHandler(internals, workflowId, childWorkflowId, callbacks) {
|
|
22
|
+
registerCancelHandler(internals, workflowId, () => callbacks.getHandle(childWorkflowId).cancel());
|
|
23
|
+
}
|
|
24
|
+
export async function rehydrateChildCancellationHandlers(internals, workflowId, callbacks) {
|
|
25
|
+
for await (const [key] of internals.storage.scan(KEYS.childCancellationPrefix(workflowId))) {
|
|
26
|
+
const childWorkflowId = decodeChildCancellationKey(workflowId, key);
|
|
27
|
+
if (childWorkflowId === null)
|
|
28
|
+
continue;
|
|
29
|
+
registerChildCancellationHandler(internals, workflowId, childWorkflowId, callbacks);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function decodeChildCancellationKey(workflowId, key) {
|
|
33
|
+
const prefix = KEYS.childCancellationPrefix(workflowId);
|
|
34
|
+
if (!key.startsWith(prefix))
|
|
35
|
+
return null;
|
|
36
|
+
const encodedChildWorkflowId = key.slice(prefix.length);
|
|
37
|
+
if (encodedChildWorkflowId.length === 0 || encodedChildWorkflowId.includes(":"))
|
|
38
|
+
return null;
|
|
39
|
+
return decodeStorageKeyComponent(encodedChildWorkflowId);
|
|
40
|
+
}
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import { assertOnTerminalConflictUnsupported } from "../start-workflow-validation.js";
|
|
2
|
+
import { stageAtomicWorkflowCommitSideEffects } from "./checkpoint-side-effects.js";
|
|
3
|
+
import {
|
|
4
|
+
buildChildCancellationOperations,
|
|
5
|
+
registerChildCancellationHandler
|
|
6
|
+
} from "./child-workflow-cancellation.js";
|
|
1
7
|
import { WorkflowAlreadyExistsError } from "./errors.js";
|
|
2
8
|
import { encodedValuesEqual } from "./state-utilities.js";
|
|
3
9
|
export async function processChildWorkflowOperation(internals, workflowId, operation, callbacks) {
|
|
@@ -37,6 +43,7 @@ async function resolveCollisionChildHandle(childWorkflowId, operation, execution
|
|
|
37
43
|
return callbacks.getHandle(childWorkflowId);
|
|
38
44
|
}
|
|
39
45
|
async function dispatchChildWorkflowStart(internals, childWorkflowId, operation, context, callbacks) {
|
|
46
|
+
assertOnTerminalConflictUnsupported(operation.options, "ctx.startChild");
|
|
40
47
|
applyPendingChildExecutionContext(internals, context);
|
|
41
48
|
try {
|
|
42
49
|
return await callbacks.start(operation.workflowType, operation.input, {
|
|
@@ -45,19 +52,29 @@ async function dispatchChildWorkflowStart(internals, childWorkflowId, operation,
|
|
|
45
52
|
} catch (error) {
|
|
46
53
|
if (!(error instanceof WorkflowAlreadyExistsError))
|
|
47
54
|
throw error;
|
|
48
|
-
return resolveCollisionChildHandle(childWorkflowId, operation, context.pendingExecutionStateOwnerId, error, callbacks);
|
|
55
|
+
return resolveCollisionChildHandle(childWorkflowId, operation, context.pendingExecutionStateOwnerId ?? void 0, error, callbacks);
|
|
49
56
|
} finally {
|
|
50
57
|
clearPendingChildExecutionContext(internals, context);
|
|
51
58
|
}
|
|
52
59
|
}
|
|
53
60
|
export async function executeChildWorkflow(internals, workflowId, operation, currentDepth, callbacks) {
|
|
54
|
-
const rawId = operation.options?.id, childWorkflowId = typeof rawId === "string" ? rawId : crypto.randomUUID(), parentHeaders = internals.workflowHeaders.get(workflowId) ?? new Map,
|
|
61
|
+
const rawId = operation.options?.id, childWorkflowId = typeof rawId === "string" ? rawId : crypto.randomUUID(), parentHeaders = internals.workflowHeaders.get(workflowId) ?? new Map, parentState = await callbacks.loadWorkflowState(workflowId), parentClosePolicy = resolveChildWorkflowParentClosePolicy(operation), executionStateOwnerId = parentClosePolicy === "abandon" ? null : parentState?.executionStateOwnerId ?? workflowId, executeChild = async () => {
|
|
55
62
|
const context = {
|
|
56
63
|
pendingNestingDepth: currentDepth + 1,
|
|
57
64
|
pendingParentHeaders: internals.workflowHeaders.get(workflowId),
|
|
58
65
|
pendingExecutionStateOwnerId: executionStateOwnerId
|
|
59
|
-
};
|
|
60
|
-
|
|
66
|
+
}, childHandle = await dispatchChildWorkflowStart(internals, childWorkflowId, operation, context, callbacks);
|
|
67
|
+
if (parentClosePolicy === "abandon")
|
|
68
|
+
return createChildWorkflowHandleReference(childHandle.id);
|
|
69
|
+
if (parentClosePolicy === "request-cancel") {
|
|
70
|
+
stageAtomicWorkflowCommitSideEffects(internals, workflowId, {
|
|
71
|
+
conditions: [],
|
|
72
|
+
operations: buildChildCancellationOperations(internals, workflowId, childHandle.id)
|
|
73
|
+
});
|
|
74
|
+
registerChildCancellationHandler(internals, workflowId, childHandle.id, callbacks);
|
|
75
|
+
return createChildWorkflowHandleReference(childHandle.id);
|
|
76
|
+
}
|
|
77
|
+
return childHandle.result();
|
|
61
78
|
}, composedInterceptor = callbacks.getComposedWorkflowInterceptor();
|
|
62
79
|
if (!composedInterceptor)
|
|
63
80
|
return executeChild();
|
|
@@ -70,3 +87,9 @@ export async function executeChildWorkflow(internals, workflowId, operation, cur
|
|
|
70
87
|
parentHeaders
|
|
71
88
|
}, executeChild);
|
|
72
89
|
}
|
|
90
|
+
function resolveChildWorkflowParentClosePolicy(operation) {
|
|
91
|
+
return operation.options?.parentClosePolicy ?? "await";
|
|
92
|
+
}
|
|
93
|
+
function createChildWorkflowHandleReference(workflowId) {
|
|
94
|
+
return { id: workflowId };
|
|
95
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { EngineInternals } from './internals.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Re-drive every in-process `ctx.waitUntil` waiter registered for a workflow.
|
|
4
|
+
* Called after an inline `onUpdate` handler runs (`tryInlineUpdateHandler`),
|
|
5
|
+
* since the handler may have mutated the workflow-local state a predicate reads.
|
|
6
|
+
* Each call wakes the parked `processWaitConditionOperation`, which re-evaluates
|
|
7
|
+
* its predicate against the (possibly mutated) state.
|
|
8
|
+
*
|
|
9
|
+
* Weft signals are pull-only (`ctx.waitForSignal`) and run no state-mutating
|
|
10
|
+
* handler, so signal delivery is intentionally NOT a re-drive trigger — `onUpdate`
|
|
11
|
+
* is the push path. Lives in its own module so `updates.ts` can call it without
|
|
12
|
+
* an import cycle through `operations-coordination.ts`.
|
|
13
|
+
*/
|
|
14
|
+
export declare function notifyConditionWaiters(internals: EngineInternals, workflowId: string): void;
|