@lostgradient/weft 0.3.0 → 0.5.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 +61 -5
- package/dist/client/local-handles.d.ts +22 -0
- package/dist/client/local-handles.js +23 -0
- package/dist/client/local.d.ts +6 -3
- package/dist/client/local.js +12 -26
- 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 +46 -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 +136 -9
- 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 +6 -13
- package/dist/core/engine/operations-activity.js +26 -53
- package/dist/core/engine/operations-coordination.d.ts +10 -0
- package/dist/core/engine/operations-coordination.js +44 -9
- 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 +25 -6
- 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 +19 -19
- 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 +32 -32
- 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 +20 -20
- 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,7 +1,8 @@
|
|
|
1
1
|
import { KEYS } from "../../storage/interface.js";
|
|
2
|
-
import { decode
|
|
2
|
+
import { decode } from "../codec.js";
|
|
3
3
|
import { WorkflowNotRegisteredError } from "./errors.js";
|
|
4
4
|
import { ScheduleHandle } from "./schedule-handle.js";
|
|
5
|
+
import { resolveEffectiveScheduleFireAt } from "./schedule-jitter.js";
|
|
5
6
|
import { getNextScheduleOccurrence } from "./schedule-occurrence.js";
|
|
6
7
|
import {
|
|
7
8
|
clearScheduleCurrentWorkflow,
|
|
@@ -18,6 +19,7 @@ import {
|
|
|
18
19
|
normalizeScheduleOptions,
|
|
19
20
|
normalizeScheduleSpec
|
|
20
21
|
} from "./validation/schedule.js";
|
|
22
|
+
export { startScheduledRun } from "./schedule-run.js";
|
|
21
23
|
export { handleScheduleTimer } from "./schedule-timer.js";
|
|
22
24
|
export async function schedule(internals, type, input, spec, options) {
|
|
23
25
|
if (!internals.registrations.has(type))
|
|
@@ -37,9 +39,11 @@ export async function schedule(internals, type, input, spec, options) {
|
|
|
37
39
|
status: "active",
|
|
38
40
|
overlap: normalizedOptions.overlap,
|
|
39
41
|
backfill: normalizedOptions.backfill,
|
|
42
|
+
...normalizedOptions.jitterMs !== void 0 && { jitterMs: normalizedOptions.jitterMs },
|
|
40
43
|
createdAt: now,
|
|
41
44
|
updatedAt: now,
|
|
42
45
|
nextFireAt: getNextScheduleOccurrence({ ...cadenceFields, createdAt: now }, now),
|
|
46
|
+
missedFireCount: 0,
|
|
43
47
|
queuedRuns: 0
|
|
44
48
|
};
|
|
45
49
|
await writeScheduleState(internals, state);
|
|
@@ -61,6 +65,28 @@ export async function listSchedules(internals, filter) {
|
|
|
61
65
|
}
|
|
62
66
|
return paginateScheduleSummaries(items, normalizedFilter);
|
|
63
67
|
}
|
|
68
|
+
export async function recoverOrphanedScheduleTimers(internals) {
|
|
69
|
+
for await (const [key, value] of internals.storage.scan("schedule:")) {
|
|
70
|
+
if (key.slice(9).includes(":"))
|
|
71
|
+
continue;
|
|
72
|
+
const state = decodeScheduleState(value);
|
|
73
|
+
if (!isActiveScheduleWithTimer(state))
|
|
74
|
+
continue;
|
|
75
|
+
if (await hasCurrentScheduleTimer(internals, state))
|
|
76
|
+
continue;
|
|
77
|
+
await writeScheduleState(internals, state);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function isActiveScheduleWithTimer(state) {
|
|
81
|
+
return state?.status === "active" && state.nextFireAt !== null;
|
|
82
|
+
}
|
|
83
|
+
async function hasCurrentScheduleTimer(internals, state) {
|
|
84
|
+
const timerKey = KEYS.scheduleTick(resolveEffectiveScheduleFireAt(state, state.nextFireAt), state.id);
|
|
85
|
+
if (await internals.storage.get(timerKey) === null)
|
|
86
|
+
return !1;
|
|
87
|
+
const timerIndexBytes = await internals.storage.get(`timer-idx:${createScheduleTimerId(state.id)}`);
|
|
88
|
+
return timerIndexBytes !== null && decode(timerIndexBytes) === timerKey;
|
|
89
|
+
}
|
|
64
90
|
export function toScheduleSummary(state) {
|
|
65
91
|
const { input: _input, ...summary } = state;
|
|
66
92
|
return summary;
|
|
@@ -107,10 +133,7 @@ export async function cancelSchedule(internals, scheduleId) {
|
|
|
107
133
|
await writeScheduleState(internals, updatedState, { includeTimer: !1 });
|
|
108
134
|
}
|
|
109
135
|
export async function updateSchedule(internals, scheduleId, newSpec) {
|
|
110
|
-
const normalizedScheduleId = coerceScheduleId(scheduleId, "scheduleId"), normalizedSpec = normalizeScheduleSpec(newSpec), state = await requireScheduleState(internals, normalizedScheduleId)
|
|
111
|
-
if (state.status === "active")
|
|
112
|
-
await internals.scheduler.cancel(createScheduleTimerId(normalizedScheduleId), normalizedScheduleId);
|
|
113
|
-
const now = internals.options.getNow(), {
|
|
136
|
+
const normalizedScheduleId = coerceScheduleId(scheduleId, "scheduleId"), normalizedSpec = normalizeScheduleSpec(newSpec), state = await requireScheduleState(internals, normalizedScheduleId), now = internals.options.getNow(), {
|
|
114
137
|
cronExpression: _droppedCron,
|
|
115
138
|
intervalMs: _droppedInterval,
|
|
116
139
|
...stateWithoutCadence
|
|
@@ -139,36 +162,34 @@ export async function refreshScheduledWorkflowState(internals, state, callbacks)
|
|
|
139
162
|
currentWorkflowState: currentWorkflowState ?? null
|
|
140
163
|
};
|
|
141
164
|
}
|
|
142
|
-
export async function startScheduledRun(_internals, state, callbacks) {
|
|
143
|
-
const workflowId = crypto.randomUUID(), scheduleRunOperations = state.overlap === "allow" ? void 0 : [{ type: "put", key: KEYS.scheduleRun(workflowId), value: encode(state.id) }];
|
|
144
|
-
await callbacks.startWorkflow(state.workflowType, state.input, { id: workflowId }, scheduleRunOperations);
|
|
145
|
-
return workflowId;
|
|
146
|
-
}
|
|
147
165
|
function hasActiveScheduledWorkflow(currentWorkflowState) {
|
|
148
166
|
return scheduledRunOccupiesSlot(currentWorkflowState);
|
|
149
167
|
}
|
|
150
|
-
async function applyBlockedScheduleOccurrence(state, hasActiveWorkflow, callbacks) {
|
|
168
|
+
async function applyBlockedScheduleOccurrence(state, hasActiveWorkflow, callbacks, occurrence) {
|
|
151
169
|
if (!hasActiveWorkflow)
|
|
152
|
-
return { ...state, currentWorkflowId: await callbacks.startScheduledRun(state) };
|
|
170
|
+
return { ...state, currentWorkflowId: await callbacks.startScheduledRun(state, occurrence) };
|
|
153
171
|
if (state.overlap === "cancel-running") {
|
|
154
172
|
if (state.currentWorkflowId) {
|
|
155
173
|
callbacks.getWorkflowResult(state.currentWorkflowId).catch(() => {});
|
|
156
174
|
await callbacks.cancelWorkflow(state.currentWorkflowId);
|
|
157
175
|
}
|
|
158
176
|
const stateForStart = clearScheduleCurrentWorkflow(state);
|
|
159
|
-
return {
|
|
177
|
+
return {
|
|
178
|
+
...state,
|
|
179
|
+
currentWorkflowId: await callbacks.startScheduledRun(stateForStart, occurrence)
|
|
180
|
+
};
|
|
160
181
|
}
|
|
161
182
|
if (state.overlap === "queue")
|
|
162
183
|
return { ...state, queuedRuns: state.queuedRuns + 1 };
|
|
163
184
|
return state;
|
|
164
185
|
}
|
|
165
|
-
export async function applyScheduleOccurrence(_internals, state, callbacks) {
|
|
186
|
+
export async function applyScheduleOccurrence(_internals, state, callbacks, occurrence) {
|
|
166
187
|
const { state: refreshedState, currentWorkflowState } = await callbacks.refreshScheduledWorkflowState(state), hasActiveWorkflow = hasActiveScheduledWorkflow(currentWorkflowState);
|
|
167
188
|
if (refreshedState.overlap === "allow") {
|
|
168
|
-
await callbacks.startScheduledRun(refreshedState);
|
|
189
|
+
await callbacks.startScheduledRun(refreshedState, occurrence);
|
|
169
190
|
return refreshedState;
|
|
170
191
|
}
|
|
171
|
-
return applyBlockedScheduleOccurrence(refreshedState, hasActiveWorkflow, callbacks);
|
|
192
|
+
return applyBlockedScheduleOccurrence(refreshedState, hasActiveWorkflow, callbacks, occurrence);
|
|
172
193
|
}
|
|
173
194
|
export async function settleBackfillScheduleState(internals, state, callbacks) {
|
|
174
195
|
if (!state.currentWorkflowId)
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ListFilter, SearchAttributeValue } from '../types.ts';
|
|
2
|
+
import type { EngineInternals } from './internals.ts';
|
|
3
|
+
export declare function readSearchAttributesForStates(internals: EngineInternals, stateBytesList: readonly (Uint8Array | null)[], filter: ListFilter | undefined): Promise<Map<string, Record<string, SearchAttributeValue> | null>>;
|
|
4
|
+
export declare function readSearchAttributesForFilter(internals: EngineInternals, workflowId: string, filter: ListFilter | undefined): Promise<Record<string, SearchAttributeValue> | null>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { KEYS } from "../../storage/interface.js";
|
|
2
|
+
import { decodeSearchAttributeRecord, listFilterHasAttributeFilters } from "./state-utilities.js";
|
|
3
|
+
import { decodeWorkflowState } from "./validation.js";
|
|
4
|
+
export async function readSearchAttributesForStates(internals, stateBytesList, filter) {
|
|
5
|
+
const searchAttributesByWorkflowId = new Map;
|
|
6
|
+
if (!listFilterHasAttributeFilters(filter))
|
|
7
|
+
return searchAttributesByWorkflowId;
|
|
8
|
+
const states = stateBytesList.flatMap((stateBytes) => stateBytes === null ? [] : [decodeWorkflowState(stateBytes)]), attributeBytesList = await Promise.all(states.map((state) => internals.storage.get(KEYS.attribute(state.id))));
|
|
9
|
+
for (let index = 0;index < states.length; index += 1)
|
|
10
|
+
searchAttributesByWorkflowId.set(states[index].id, decodeSearchAttributeRecord(attributeBytesList[index] ?? null));
|
|
11
|
+
return searchAttributesByWorkflowId;
|
|
12
|
+
}
|
|
13
|
+
export async function readSearchAttributesForFilter(internals, workflowId, filter) {
|
|
14
|
+
if (!listFilterHasAttributeFilters(filter))
|
|
15
|
+
return null;
|
|
16
|
+
return decodeSearchAttributeRecord(await internals.storage.get(KEYS.attribute(workflowId)));
|
|
17
|
+
}
|
|
@@ -43,8 +43,14 @@ export declare function bufferSignalPayloads(internals: EngineInternals, workflo
|
|
|
43
43
|
* `sigres:` key and short-circuits instead of re-delivering, which is what
|
|
44
44
|
* guarantees "one signal per signalId" across the create and signal paths.
|
|
45
45
|
*
|
|
46
|
-
* Returns both the put operations and the CAS condition
|
|
47
|
-
*
|
|
46
|
+
* Returns both the put operations and the CAS condition. The condition gates on
|
|
47
|
+
* the `sigres:` accepted-response marker (the dedup identity, keyed by signalId
|
|
48
|
+
* alone), NOT the `sig:` payload key: the FIFO sort-class (#458) makes the
|
|
49
|
+
* start-signal's `sig:` key (class `0`) differ from the live signal path's (class
|
|
50
|
+
* `1`), so a `sig:`-keyed CAS would no longer collide with a pre-buffered signal
|
|
51
|
+
* of the same signalId and would buffer a second copy. The class-independent
|
|
52
|
+
* `sigres:` marker is what both paths share, so gating on it preserves "one
|
|
53
|
+
* signal per signalId" across the create and signal paths.
|
|
48
54
|
*/
|
|
49
55
|
export declare function buildCreateBatchSignalOperations(internals: EngineInternals, workflowId: string, signalName: string, payload: unknown, signalId: string): {
|
|
50
56
|
operations: BatchOperation[];
|
|
@@ -55,6 +61,16 @@ export declare function buildCreateBatchSignalOperations(internals: EngineIntern
|
|
|
55
61
|
};
|
|
56
62
|
export declare function hasBufferedSignal(internals: EngineInternals, workflowId: string, signalName: string): Promise<boolean>;
|
|
57
63
|
export declare function consumeSignal(internals: EngineInternals, workflowId: string, signalName: string): Promise<ConsumedSignalResult>;
|
|
64
|
+
export declare function consumeSignalWithAtomicWorkflowCommit(internals: EngineInternals, workflowId: string, signalName: string): Promise<ConsumedSignalResult>;
|
|
65
|
+
/**
|
|
66
|
+
* Read the first buffered signal payload WITHOUT deleting it. Use when a caller
|
|
67
|
+
* must check for a buffered signal but might not end up consuming it — e.g. a
|
|
68
|
+
* `ctx.race` / `ctx.all` wait-signal branch that could lose, where a destructive
|
|
69
|
+
* {@link consumeSignal} on the losing path would silently drop the signal. The
|
|
70
|
+
* winner calls {@link consumeSignalWithAtomicWorkflowCommit} to stage the
|
|
71
|
+
* durable delete into the checkpoint batch.
|
|
72
|
+
*/
|
|
73
|
+
export declare function peekSignal(internals: EngineInternals, workflowId: string, signalName: string): Promise<ConsumedSignalResult>;
|
|
58
74
|
/** Register a waiter key in a workflow-keyed reverse index. */
|
|
59
75
|
export declare function trackWaiterKey(reverseIndex: Map<string, TrackedWaiterKeys>, workflowId: string, waiterKey: string): void;
|
|
60
76
|
/** Remove a waiter key from a workflow-keyed reverse index. */
|
|
@@ -9,8 +9,9 @@ import { SignalReceivedEvent } from "../events.js";
|
|
|
9
9
|
import { encodePayloadWithinLimit } from "../payload-size.js";
|
|
10
10
|
import { validateSignalId } from "../signal-id.js";
|
|
11
11
|
import { commitAnonymousSignalOperations } from "./anonymous-signal-sequence.js";
|
|
12
|
+
import { stageAtomicWorkflowCommitSideEffects } from "./checkpoint-side-effects.js";
|
|
12
13
|
import { isTerminalWorkflowStatus } from "./validation.js";
|
|
13
|
-
const EMPTY_STORAGE_VALUE = new Uint8Array(0), SIGNAL_ACCEPTED_RESPONSE = { ok: !0 };
|
|
14
|
+
const EMPTY_STORAGE_VALUE = new Uint8Array(0), SIGNAL_ACCEPTED_RESPONSE = { ok: !0 }, SIGNAL_KEY_COMPONENT_COUNT = 5;
|
|
14
15
|
export async function signal(internals, workflowId, name, payload, callbacks, options = {}) {
|
|
15
16
|
const deliverSignal = async (targetWorkflowId, signalName, signalPayload) => {
|
|
16
17
|
await bufferSignalPayloads(internals, targetWorkflowId, [{ signalName, payload: signalPayload }], callbacks, options);
|
|
@@ -65,10 +66,8 @@ export async function bufferSignalPayloads(internals, workflowId, deliveries, ca
|
|
|
65
66
|
const delivery = deliveries[0], acceptedResponseKey = KEYS.signalAcceptedResponse(workflowId, delivery.signalName, signalId), acceptedResponse = encode(SIGNAL_ACCEPTED_RESPONSE);
|
|
66
67
|
if (await internals.storage.get(acceptedResponseKey) !== null)
|
|
67
68
|
return;
|
|
68
|
-
if (!await storageConditionalBatch(internals.storage, [{ key:
|
|
69
|
-
await ensureDuplicateSignalAcceptedResponse(internals, acceptedResponseKey, acceptedResponse);
|
|
69
|
+
if (!await storageConditionalBatch(internals.storage, [{ key: acceptedResponseKey, expectedValue: null }], [...operations, { type: "put", key: acceptedResponseKey, value: acceptedResponse }]))
|
|
70
70
|
return;
|
|
71
|
-
}
|
|
72
71
|
markTerminalCleanupTracked(internals, workflowId);
|
|
73
72
|
deliverBufferedSignals(internals, workflowId, deliveries, callbacks);
|
|
74
73
|
return;
|
|
@@ -85,7 +84,7 @@ function createExplicitSignalOperations(internals, workflowId, deliveries, signa
|
|
|
85
84
|
}
|
|
86
85
|
export function buildCreateBatchSignalOperations(internals, workflowId, signalName, payload, signalId) {
|
|
87
86
|
validateSignalId(signalId);
|
|
88
|
-
const signalKey = KEYS.
|
|
87
|
+
const signalKey = KEYS.startSignal(workflowId, signalName, signalId), acceptedResponseKey = KEYS.signalAcceptedResponse(workflowId, signalName, signalId);
|
|
89
88
|
return {
|
|
90
89
|
operations: [
|
|
91
90
|
{
|
|
@@ -95,7 +94,7 @@ export function buildCreateBatchSignalOperations(internals, workflowId, signalNa
|
|
|
95
94
|
},
|
|
96
95
|
{ type: "put", key: acceptedResponseKey, value: encode(SIGNAL_ACCEPTED_RESPONSE) }
|
|
97
96
|
],
|
|
98
|
-
condition: { key:
|
|
97
|
+
condition: { key: acceptedResponseKey, expectedValue: null }
|
|
99
98
|
};
|
|
100
99
|
}
|
|
101
100
|
function appendTerminalCleanupOperation(internals, workflowId, operations) {
|
|
@@ -130,18 +129,45 @@ function deliverBufferedSignals(internals, workflowId, deliveries, callbacks) {
|
|
|
130
129
|
callbacks.resumeParkedInlineWorkflow(workflowId);
|
|
131
130
|
}
|
|
132
131
|
export async function hasBufferedSignal(internals, workflowId, signalName) {
|
|
133
|
-
|
|
134
|
-
for await (const _entry of internals.storage.scan(prefix, { limit: 1 }))
|
|
135
|
-
return !0;
|
|
136
|
-
return !1;
|
|
132
|
+
return await findBufferedSignalRecord(internals, workflowId, signalName) !== null;
|
|
137
133
|
}
|
|
138
134
|
export async function consumeSignal(internals, workflowId, signalName) {
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
}
|
|
144
|
-
|
|
135
|
+
const record = await findBufferedSignalRecord(internals, workflowId, signalName);
|
|
136
|
+
if (record === null)
|
|
137
|
+
return { found: !1 };
|
|
138
|
+
await internals.storage.delete(record.key);
|
|
139
|
+
return { found: !0, payload: decode(record.value) };
|
|
140
|
+
}
|
|
141
|
+
export async function consumeSignalWithAtomicWorkflowCommit(internals, workflowId, signalName) {
|
|
142
|
+
const record = await findBufferedSignalRecord(internals, workflowId, signalName);
|
|
143
|
+
if (record === null)
|
|
144
|
+
return { found: !1 };
|
|
145
|
+
stageAtomicWorkflowCommitSideEffects(internals, workflowId, {
|
|
146
|
+
conditions: [{ key: record.key, expectedValue: new Uint8Array(record.value) }],
|
|
147
|
+
operations: [{ type: "delete", key: record.key }]
|
|
148
|
+
});
|
|
149
|
+
return { found: !0, payload: decode(record.value) };
|
|
150
|
+
}
|
|
151
|
+
export async function peekSignal(internals, workflowId, signalName) {
|
|
152
|
+
const record = await findBufferedSignalRecord(internals, workflowId, signalName);
|
|
153
|
+
return record === null ? { found: !1 } : { found: !0, payload: decode(record.value) };
|
|
154
|
+
}
|
|
155
|
+
async function findBufferedSignalRecord(internals, workflowId, signalName) {
|
|
156
|
+
const encodedWorkflowId = encodeStorageKeyComponent(workflowId), encodedSignalName = encodeStorageKeyComponent(signalName), encodedPrefix = signalKeyPrefix(encodedWorkflowId, encodedSignalName);
|
|
157
|
+
return await findBufferedSignalRecordByPrefix(internals, encodedPrefix, encodedWorkflowId, encodedSignalName);
|
|
158
|
+
}
|
|
159
|
+
async function findBufferedSignalRecordByPrefix(internals, prefix, encodedWorkflowId, signalNameKeyComponent) {
|
|
160
|
+
for await (const [key, value] of internals.storage.scan(prefix, { limit: 1 }))
|
|
161
|
+
if (isExactSignalKey(key, encodedWorkflowId, signalNameKeyComponent))
|
|
162
|
+
return { key, value };
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
function signalKeyPrefix(encodedWorkflowId, signalNameKeyComponent) {
|
|
166
|
+
return `sig:${encodedWorkflowId}:${signalNameKeyComponent}:`;
|
|
167
|
+
}
|
|
168
|
+
function isExactSignalKey(key, encodedWorkflowId, signalNameKeyComponent) {
|
|
169
|
+
const components = key.split(":");
|
|
170
|
+
return components.length === SIGNAL_KEY_COMPONENT_COUNT && components[0] === "sig" && components[1] === encodedWorkflowId && components[2] === signalNameKeyComponent && (components[3] === "0" || components[3] === "1") && components[4] !== "";
|
|
145
171
|
}
|
|
146
172
|
function getSingleSignalId(deliveries, defaultOptions) {
|
|
147
173
|
if (deliveries.length !== 1)
|
|
@@ -159,11 +185,6 @@ function validateSignalIdsBeforeKeyConstruction(deliveries, defaultOptions, sing
|
|
|
159
185
|
validateSignalId(deliverySignalId);
|
|
160
186
|
}
|
|
161
187
|
}
|
|
162
|
-
async function ensureDuplicateSignalAcceptedResponse(internals, acceptedResponseKey, acceptedResponse) {
|
|
163
|
-
if (await internals.storage.get(acceptedResponseKey) !== null)
|
|
164
|
-
return;
|
|
165
|
-
await storageConditionalBatch(internals.storage, [{ key: acceptedResponseKey, expectedValue: null }], [{ type: "put", key: acceptedResponseKey, value: acceptedResponse }]);
|
|
166
|
-
}
|
|
167
188
|
export function trackWaiterKey(reverseIndex, workflowId, waiterKey) {
|
|
168
189
|
let keys = reverseIndex.get(workflowId);
|
|
169
190
|
if (!keys) {
|
|
@@ -1,5 +1,49 @@
|
|
|
1
1
|
import type { ContextOperationRequest } from '../context.ts';
|
|
2
|
-
import type { ListFilter, PaginatedResult, ScheduleFilter, ScheduleState, ScheduleSummary, WorkflowState, WorkflowSummary } from '../types.ts';
|
|
2
|
+
import type { AttributeFilter, AttributeFilterScalarValue, ListFilter, PaginatedResult, ScheduleFilter, ScheduleState, ScheduleSummary, SearchAttributeValue, WorkflowState, WorkflowSummary } from '../types.ts';
|
|
3
|
+
/**
|
|
4
|
+
* Durable execution-claim record stored at {@link KEYS.teardownOwed} for a workflow
|
|
5
|
+
* that owes an engine-driven finalizer run (issue #446 Phase 2). A holder fenced-CAS's
|
|
6
|
+
* it from `'owed'` to `'running'` before invoking the finalizer, then back to `'owed'`
|
|
7
|
+
* (with `attempts` bumped) on a retryable failure, or deletes it on success/dead-letter.
|
|
8
|
+
*
|
|
9
|
+
* Liveness is decided by TIME, not by an in-memory set or a lease epoch: a `'running'`
|
|
10
|
+
* claim is reclaimable once `claimedAt` is older than the stale threshold (the
|
|
11
|
+
* finalizer's per-attempt timeout plus a margin — see `teardownStaleThresholdMs`). This
|
|
12
|
+
* makes crash recovery an ordinary stale-claim retry with no special re-hydration: a
|
|
13
|
+
* fresh process simply re-fires the surviving timer and reclaims the stale `'running'`
|
|
14
|
+
* marker. The cost is that a finalizer running past the threshold may be re-driven
|
|
15
|
+
* concurrently, which is why workflow finalizers must be idempotent.
|
|
16
|
+
*
|
|
17
|
+
* - `status`: `'owed'` until claimed, `'running'` while a holder is executing it.
|
|
18
|
+
* - `attempts`: count of finalizer attempts so far (`0` until the first claim).
|
|
19
|
+
* - `token`: ties the marker to its `wf-teardown:` timer so a stale timer for a
|
|
20
|
+
* re-armed (different-token) claim cannot drive it.
|
|
21
|
+
* - `claimedAt`: engine clock at the `owed → running` transition; `undefined` while
|
|
22
|
+
* `'owed'`. Drives the time-based reclaim of an abandoned `'running'` claim.
|
|
23
|
+
*/
|
|
24
|
+
export type TeardownClaim = {
|
|
25
|
+
status: 'owed' | 'running';
|
|
26
|
+
attempts: number;
|
|
27
|
+
token: string;
|
|
28
|
+
claimedAt?: number;
|
|
29
|
+
};
|
|
30
|
+
/** Build the durable teardown timer id from its claim token (parsed by {@link parseTeardownTimerId}). */
|
|
31
|
+
export declare function createTeardownTimerId(token: string): string;
|
|
32
|
+
/** Recover the claim token from a teardown timer id, or `null` when the id is malformed. */
|
|
33
|
+
export declare function parseTeardownTimerId(timerId: string): string | null;
|
|
34
|
+
/**
|
|
35
|
+
* Runtime type guard for a decoded {@link TeardownClaim} read back from storage.
|
|
36
|
+
*
|
|
37
|
+
* `attempts` must be a non-negative SAFE INTEGER and `claimedAt` (when present) a
|
|
38
|
+
* finite non-negative number — not merely `typeof === 'number'`. A persisted `NaN`
|
|
39
|
+
* or `Infinity` would otherwise drive the marker forever: `attempt >= MAX_TEARDOWN_ATTEMPTS`
|
|
40
|
+
* is always false for `NaN` (never dead-letters) and `now - claimedAt >= threshold` never
|
|
41
|
+
* holds for a non-finite `claimedAt` (never reclaims a stale running claim). Rejecting them
|
|
42
|
+
* here routes a corrupt-but-claim-shaped marker through the clear path instead. `claimedAt`
|
|
43
|
+
* is checked with `isFinite` rather than `isSafeInteger` because `getNow()` may return a
|
|
44
|
+
* fractional timestamp.
|
|
45
|
+
*/
|
|
46
|
+
export declare function isTeardownClaim(value: unknown): value is TeardownClaim;
|
|
3
47
|
type PaginationFilter = {
|
|
4
48
|
limit?: number;
|
|
5
49
|
offset?: number;
|
|
@@ -34,7 +78,10 @@ export declare function encodeWorkflowStartHeaders(headers: Map<string, string>)
|
|
|
34
78
|
export declare function decodeWorkflowStartHeaders(bytes: Uint8Array): Map<string, string>;
|
|
35
79
|
export declare function selectPersistedWorkflowStartHeaders(headers: Map<string, string> | undefined): Map<string, string> | undefined;
|
|
36
80
|
export declare function intersectIdentifierSets(idSets: Set<string>[]): Set<string> | null;
|
|
37
|
-
export declare function
|
|
81
|
+
export declare function listFilterHasAttributeFilters(filter: ListFilter | undefined): boolean;
|
|
82
|
+
export declare function decodeSearchAttributeRecord(attributeBytes: Uint8Array | null): Record<string, SearchAttributeValue> | null;
|
|
83
|
+
export declare function attributeFilterExactValues(filter: AttributeFilter): readonly AttributeFilterScalarValue[] | null;
|
|
84
|
+
export declare function matchesListFilter(state: WorkflowState, filter: ListFilter | undefined, constrainedIds: Set<string> | null, normalizedTagFilters: readonly string[] | undefined, searchAttributes?: Readonly<Record<string, SearchAttributeValue>> | null): boolean;
|
|
38
85
|
/**
|
|
39
86
|
* Slice an in-memory list of {@link WorkflowSummary} into a {@link PaginatedResult}.
|
|
40
87
|
*
|
|
@@ -1,8 +1,32 @@
|
|
|
1
1
|
import { decode, encode } from "../codec.js";
|
|
2
2
|
import { isRecord, safeDebugStringify, sanitizeDebugValueForDisplay } from "../debug-output.js";
|
|
3
|
+
import { encodeAttributeValue } from "../search-attributes.js";
|
|
4
|
+
import { searchAttributeName } from "../types.js";
|
|
3
5
|
import { matchesWorkflowTagFilter } from "../workflow-tags.js";
|
|
6
|
+
import { stripInternalCheckpointReplayPayload } from "./checkpoint-replay.js";
|
|
4
7
|
import { isPlainObjectRecord, isSanitizedSearchAttributeValue } from "./validation.js";
|
|
5
|
-
const PERSISTED_WORKFLOW_START_HEADER_NAMES = new Set(["traceparent", "tracestate"]), PRESERVE_OUTPUT_TERMINAL_CLEANUP_TIMER_PREFIX = "terminal-cleanup:preserve-output:", FULL_TERMINAL_CLEANUP_TIMER_PREFIX = "terminal-cleanup:full:";
|
|
8
|
+
const PERSISTED_WORKFLOW_START_HEADER_NAMES = new Set(["traceparent", "tracestate"]), PRESERVE_OUTPUT_TERMINAL_CLEANUP_TIMER_PREFIX = "terminal-cleanup:preserve-output:", FULL_TERMINAL_CLEANUP_TIMER_PREFIX = "terminal-cleanup:full:", TEARDOWN_TIMER_PREFIX = "teardown:";
|
|
9
|
+
export function createTeardownTimerId(token) {
|
|
10
|
+
return `${TEARDOWN_TIMER_PREFIX}${token}`;
|
|
11
|
+
}
|
|
12
|
+
export function parseTeardownTimerId(timerId) {
|
|
13
|
+
if (!timerId.startsWith(TEARDOWN_TIMER_PREFIX))
|
|
14
|
+
return null;
|
|
15
|
+
const token = timerId.slice(TEARDOWN_TIMER_PREFIX.length);
|
|
16
|
+
return token.length === 0 ? null : token;
|
|
17
|
+
}
|
|
18
|
+
export function isTeardownClaim(value) {
|
|
19
|
+
if (typeof value !== "object" || value === null)
|
|
20
|
+
return !1;
|
|
21
|
+
const candidate = value;
|
|
22
|
+
return (candidate.status === "owed" || candidate.status === "running") && typeof candidate.token === "string" && isNonNegativeSafeInteger(candidate.attempts) && isAbsentOrFiniteNonNegative(candidate.claimedAt);
|
|
23
|
+
}
|
|
24
|
+
function isNonNegativeSafeInteger(value) {
|
|
25
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
26
|
+
}
|
|
27
|
+
function isAbsentOrFiniteNonNegative(value) {
|
|
28
|
+
return value === void 0 || typeof value === "number" && Number.isFinite(value) && value >= 0;
|
|
29
|
+
}
|
|
6
30
|
export function workflowFeedListenerKey(workflowId, selector) {
|
|
7
31
|
return `${workflowId}\x00${selector}`;
|
|
8
32
|
}
|
|
@@ -33,6 +57,8 @@ export function getTimelineOperationLabel(operation) {
|
|
|
33
57
|
return operation.signalName;
|
|
34
58
|
case "wait-update":
|
|
35
59
|
return operation.updateName;
|
|
60
|
+
case "get-version":
|
|
61
|
+
return operation.changeId;
|
|
36
62
|
case "child-workflow":
|
|
37
63
|
return operation.workflowType;
|
|
38
64
|
case "load":
|
|
@@ -84,6 +110,13 @@ export function getTimelineBasicInputSummary(operation) {
|
|
|
84
110
|
return summarizeTimelineValue({ signalName: operation.signalName });
|
|
85
111
|
case "wait-update":
|
|
86
112
|
return summarizeTimelineValue({ updateName: operation.updateName });
|
|
113
|
+
case "get-version":
|
|
114
|
+
return summarizeTimelineValue({
|
|
115
|
+
changeId: operation.changeId,
|
|
116
|
+
minSupported: operation.minSupported,
|
|
117
|
+
maxSupported: operation.maxSupported,
|
|
118
|
+
version: operation.version
|
|
119
|
+
});
|
|
87
120
|
case "parallel":
|
|
88
121
|
case "race":
|
|
89
122
|
return summarizeTimelineValue({ operationCount: operation.operations.length });
|
|
@@ -138,7 +171,7 @@ export function sanitizeCheckpointState(checkpoint) {
|
|
|
138
171
|
}
|
|
139
172
|
export function sanitizeWorkflowEventPayload(payload) {
|
|
140
173
|
const sanitized = sanitizeDebugValueForDisplay(payload);
|
|
141
|
-
return isRecord(sanitized) ? sanitized : { value: sanitized };
|
|
174
|
+
return isRecord(sanitized) ? stripInternalCheckpointReplayPayload(sanitized) : { value: sanitized };
|
|
142
175
|
}
|
|
143
176
|
export function sanitizeTimelineSummary(summary) {
|
|
144
177
|
if (summary === void 0)
|
|
@@ -207,7 +240,83 @@ function matchesListFilterFailureCategory(state, filter) {
|
|
|
207
240
|
const categories = Array.isArray(filter.failureCategory) ? filter.failureCategory : [filter.failureCategory];
|
|
208
241
|
return state.failureCategory !== void 0 && state.failureCategory !== null && categories.includes(state.failureCategory);
|
|
209
242
|
}
|
|
210
|
-
export function
|
|
243
|
+
export function listFilterHasAttributeFilters(filter) {
|
|
244
|
+
return (filter?.attributes?.length ?? 0) > 0;
|
|
245
|
+
}
|
|
246
|
+
function isSearchAttributeFilterValue(value) {
|
|
247
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean" || value instanceof Date)
|
|
248
|
+
return !0;
|
|
249
|
+
return Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
250
|
+
}
|
|
251
|
+
export function decodeSearchAttributeRecord(attributeBytes) {
|
|
252
|
+
if (attributeBytes === null)
|
|
253
|
+
return null;
|
|
254
|
+
const decoded = decode(attributeBytes);
|
|
255
|
+
if (!isPlainObjectRecord(decoded))
|
|
256
|
+
return null;
|
|
257
|
+
const attributes = {};
|
|
258
|
+
for (const [key, value] of Object.entries(decoded))
|
|
259
|
+
if (isSearchAttributeFilterValue(value))
|
|
260
|
+
attributes[key] = value;
|
|
261
|
+
return attributes;
|
|
262
|
+
}
|
|
263
|
+
export function attributeFilterExactValues(filter) {
|
|
264
|
+
if (filter.value === void 0)
|
|
265
|
+
return null;
|
|
266
|
+
if (Array.isArray(filter.value))
|
|
267
|
+
return [...filter.value];
|
|
268
|
+
return [filter.value];
|
|
269
|
+
}
|
|
270
|
+
function storedAttributeScalarValues(value) {
|
|
271
|
+
return Array.isArray(value) ? value : [value];
|
|
272
|
+
}
|
|
273
|
+
function attributeValuesEqual(actual, expected) {
|
|
274
|
+
if (actual instanceof Date || expected instanceof Date)
|
|
275
|
+
return actual instanceof Date && expected instanceof Date && actual.getTime() === expected.getTime();
|
|
276
|
+
return actual === expected;
|
|
277
|
+
}
|
|
278
|
+
function attributeValueMatchesAnyOf(actual, expectedValues) {
|
|
279
|
+
if (expectedValues.length === 0)
|
|
280
|
+
return !1;
|
|
281
|
+
for (const actualValue of storedAttributeScalarValues(actual))
|
|
282
|
+
if (expectedValues.some((expectedValue) => attributeValuesEqual(actualValue, expectedValue)))
|
|
283
|
+
return !0;
|
|
284
|
+
return !1;
|
|
285
|
+
}
|
|
286
|
+
function encodedAttributeValueSatisfiesRange(encodedValue, filter) {
|
|
287
|
+
if (filter.gte !== void 0 && encodedValue < encodeAttributeValue(filter.gte))
|
|
288
|
+
return !1;
|
|
289
|
+
if (filter.gt !== void 0 && encodedValue <= encodeAttributeValue(filter.gt))
|
|
290
|
+
return !1;
|
|
291
|
+
if (filter.lte !== void 0 && encodedValue > encodeAttributeValue(filter.lte))
|
|
292
|
+
return !1;
|
|
293
|
+
if (filter.lt !== void 0 && encodedValue >= encodeAttributeValue(filter.lt))
|
|
294
|
+
return !1;
|
|
295
|
+
return !0;
|
|
296
|
+
}
|
|
297
|
+
function attributeValueMatchesRange(value, filter) {
|
|
298
|
+
for (const scalarValue of storedAttributeScalarValues(value))
|
|
299
|
+
if (encodedAttributeValueSatisfiesRange(encodeAttributeValue(scalarValue), filter))
|
|
300
|
+
return !0;
|
|
301
|
+
return !1;
|
|
302
|
+
}
|
|
303
|
+
function matchesAttributeFilter(searchAttributes, filter) {
|
|
304
|
+
const attributeValue = searchAttributes[searchAttributeName(filter.key)];
|
|
305
|
+
if (attributeValue === void 0)
|
|
306
|
+
return !1;
|
|
307
|
+
const exactValues = attributeFilterExactValues(filter);
|
|
308
|
+
if (exactValues !== null)
|
|
309
|
+
return attributeValueMatchesAnyOf(attributeValue, exactValues);
|
|
310
|
+
return attributeValueMatchesRange(attributeValue, filter);
|
|
311
|
+
}
|
|
312
|
+
function matchesListFilterAttributes(searchAttributes, filter) {
|
|
313
|
+
if (!listFilterHasAttributeFilters(filter))
|
|
314
|
+
return !0;
|
|
315
|
+
if (searchAttributes === null || searchAttributes === void 0)
|
|
316
|
+
return !1;
|
|
317
|
+
return filter.attributes.every((attributeFilter) => matchesAttributeFilter(searchAttributes, attributeFilter));
|
|
318
|
+
}
|
|
319
|
+
export function matchesListFilter(state, filter, constrainedIds, normalizedTagFilters, searchAttributes) {
|
|
211
320
|
if (constrainedIds !== null && !constrainedIds.has(state.id))
|
|
212
321
|
return !1;
|
|
213
322
|
if (!matchesWorkflowTagFilter(state.tags, normalizedTagFilters))
|
|
@@ -220,6 +329,8 @@ export function matchesListFilter(state, filter, constrainedIds, normalizedTagFi
|
|
|
220
329
|
return !1;
|
|
221
330
|
if (!matchesListFilterFailureCategory(state, filter))
|
|
222
331
|
return !1;
|
|
332
|
+
if (!matchesListFilterAttributes(searchAttributes, filter))
|
|
333
|
+
return !1;
|
|
223
334
|
return !0;
|
|
224
335
|
}
|
|
225
336
|
function timestampInRange(value, range) {
|
|
@@ -7,8 +7,21 @@ export declare function runSerializedWorkflowStateWrite<TResult>(internals: Engi
|
|
|
7
7
|
export declare function loadWorkflowState(internals: EngineInternals, workflowId: string): Promise<WorkflowState | null>;
|
|
8
8
|
/** Load a terminal workflow result or throw the persisted terminal error. */
|
|
9
9
|
export declare function loadWorkflowResult(internals: EngineInternals, workflowId: string): Promise<unknown>;
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
type WorkflowStateCommitOptions = {
|
|
11
|
+
includePendingAtomicSideEffects?: boolean;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Commit an engine-generator-owned workflow-state advance, FENCED on the lease
|
|
15
|
+
* epoch under `ownership: 'lease'` (issue #470 Step 2). A deposed engine's write
|
|
16
|
+
* loses its CAS instead of corrupting the successor's state; the deposition is
|
|
17
|
+
* detected and the engine halts (see {@link commitFencedEngineWrite}). Under
|
|
18
|
+
* `ownership: 'none'` it is byte-for-byte the pre-Step-2 commit shape — the epoch
|
|
19
|
+
* condition is only appended when a lease is held. Use this for suspend,
|
|
20
|
+
* completion, and other state advances driven by the workflow lifecycle. Operator/
|
|
21
|
+
* external mutations (search-attribute and tag edits) do NOT use this helper; they
|
|
22
|
+
* batch directly and are intentionally never fenced.
|
|
23
|
+
*/
|
|
24
|
+
export declare function commitFencedWorkflowStateOperations(internals: EngineInternals, state: WorkflowState, operations: BatchOperation[], options?: WorkflowStateCommitOptions): Promise<void>;
|
|
12
25
|
/** Load and decode persisted schedule state by schedule ID. */
|
|
13
26
|
export declare function loadScheduleState(internals: EngineInternals, scheduleId: string): Promise<ScheduleState | null>;
|
|
14
27
|
/** Load a schedule state. */
|
|
@@ -19,3 +32,4 @@ export declare function writeScheduleState(internals: EngineInternals, state: Sc
|
|
|
19
32
|
}): Promise<void>;
|
|
20
33
|
/** Load persisted workflow start headers by workflow ID. */
|
|
21
34
|
export declare function loadWorkflowStartHeaders(internals: EngineInternals, workflowId: string): Promise<Map<string, string> | undefined>;
|
|
35
|
+
export {};
|
|
@@ -1,8 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
KEYS
|
|
3
|
+
} from "../../storage/interface.js";
|
|
2
4
|
import { encode } from "../codec.js";
|
|
3
5
|
import { buildTimerBatchOperations } from "../scheduler.js";
|
|
4
6
|
import { WorkflowTimeoutError } from "../timeouts.js";
|
|
7
|
+
import {
|
|
8
|
+
clearPendingAtomicWorkflowCommitSideEffects,
|
|
9
|
+
takePendingAtomicWorkflowCommitSideEffects
|
|
10
|
+
} from "./checkpoint-side-effects.js";
|
|
11
|
+
import { commitFencedEngineWrite } from "./fenced-write.js";
|
|
5
12
|
import { getWorkflowExecutionStartedAt } from "./handles.js";
|
|
13
|
+
import { resolveEffectiveScheduleFireAt } from "./schedule-jitter.js";
|
|
6
14
|
import { createScheduleTimerId, decodeWorkflowStartHeaders } from "./state-utilities.js";
|
|
7
15
|
import { decodeWorkflowState } from "./validation.js";
|
|
8
16
|
import { decodeScheduleState } from "./validation/schedule.js";
|
|
@@ -48,8 +56,19 @@ export async function loadWorkflowResult(internals, workflowId) {
|
|
|
48
56
|
}
|
|
49
57
|
throw Error(`Workflow "${workflowId}" is still ${state.status}`);
|
|
50
58
|
}
|
|
51
|
-
|
|
52
|
-
|
|
59
|
+
function buildWorkflowStateCommit(internals, workflowId, operations, options) {
|
|
60
|
+
const pendingSideEffects = options.includePendingAtomicSideEffects ? takePendingAtomicWorkflowCommitSideEffects(internals, workflowId) : void 0, operationsWithSideEffects = pendingSideEffects === void 0 ? operations : [...operations, ...pendingSideEffects.operations], conditions = internals.storage.capabilities().conditionalBatch ? pendingSideEffects?.conditions ?? [] : [];
|
|
61
|
+
return {
|
|
62
|
+
operations: operationsWithSideEffects,
|
|
63
|
+
conditions,
|
|
64
|
+
hasPendingSideEffects: pendingSideEffects !== void 0
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
export async function commitFencedWorkflowStateOperations(internals, state, operations, options = {}) {
|
|
68
|
+
const commit = buildWorkflowStateCommit(internals, state.id, operations, options);
|
|
69
|
+
await commitFencedEngineWrite(internals, commit.operations, commit.conditions, () => Error(`Workflow state commit for workflow "${state.id}" lost its atomic side-effect precondition.`));
|
|
70
|
+
if (commit.hasPendingSideEffects)
|
|
71
|
+
clearPendingAtomicWorkflowCommitSideEffects(internals, state.id);
|
|
53
72
|
}
|
|
54
73
|
export async function loadScheduleState(internals, scheduleId) {
|
|
55
74
|
const bytes = await internals.storage.get(KEYS.schedule(scheduleId));
|
|
@@ -65,13 +84,15 @@ export async function writeScheduleState(internals, state, options) {
|
|
|
65
84
|
const operations = [
|
|
66
85
|
{ type: "put", key: KEYS.schedule(state.id), value: encode(state) }
|
|
67
86
|
];
|
|
68
|
-
if ((options?.includeTimer ?? state.status === "active") && state.status === "active" && state.nextFireAt !== null)
|
|
87
|
+
if ((options?.includeTimer ?? state.status === "active") && state.status === "active" && state.nextFireAt !== null) {
|
|
88
|
+
const effectiveFireAt = resolveEffectiveScheduleFireAt(state, state.nextFireAt);
|
|
69
89
|
operations.push(...buildTimerBatchOperations({
|
|
70
90
|
id: createScheduleTimerId(state.id),
|
|
71
91
|
workflowId: state.id,
|
|
72
|
-
fireAt:
|
|
92
|
+
fireAt: effectiveFireAt,
|
|
73
93
|
kind: "schedule"
|
|
74
94
|
}));
|
|
95
|
+
}
|
|
75
96
|
await internals.storage.batch(operations);
|
|
76
97
|
}
|
|
77
98
|
export async function loadWorkflowStartHeaders(internals, workflowId) {
|
|
@@ -3,3 +3,5 @@ import type { StoredStreamChunk } from '../context.ts';
|
|
|
3
3
|
export declare function loadStoredStreamChunks(storage: Storage, workflowId: string, key: string, options?: {
|
|
4
4
|
after?: number;
|
|
5
5
|
}): Promise<StoredStreamChunk[]>;
|
|
6
|
+
export declare function encodeStoredStreamTailSequence(sequence: number): Uint8Array;
|
|
7
|
+
export declare function loadStoredStreamTailSequence(storage: Storage, workflowId: string, key: string): Promise<number | null>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { KEYS } from "../../storage/interface.js";
|
|
2
|
-
import { decode } from "../codec.js";
|
|
2
|
+
import { decode, encode } from "../codec.js";
|
|
3
3
|
const STREAM_CHUNK_SEQUENCE_PATTERN = /^\d+$/;
|
|
4
4
|
function parseStreamChunkSequence(sequenceText) {
|
|
5
5
|
if (!STREAM_CHUNK_SEQUENCE_PATTERN.test(sequenceText))
|
|
@@ -20,3 +20,26 @@ export async function loadStoredStreamChunks(storage, workflowId, key, options)
|
|
|
20
20
|
}
|
|
21
21
|
return chunks;
|
|
22
22
|
}
|
|
23
|
+
export function encodeStoredStreamTailSequence(sequence) {
|
|
24
|
+
return encode({ sequence });
|
|
25
|
+
}
|
|
26
|
+
function parseStoredStreamTailSequence(value) {
|
|
27
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
28
|
+
return null;
|
|
29
|
+
if (!("sequence" in value))
|
|
30
|
+
return null;
|
|
31
|
+
const sequence = value.sequence;
|
|
32
|
+
if (typeof sequence !== "number" || !Number.isSafeInteger(sequence) || sequence < -1)
|
|
33
|
+
return null;
|
|
34
|
+
return sequence;
|
|
35
|
+
}
|
|
36
|
+
export async function loadStoredStreamTailSequence(storage, workflowId, key) {
|
|
37
|
+
const bytes = await storage.get(KEYS.streamTail(workflowId, key));
|
|
38
|
+
if (bytes === null)
|
|
39
|
+
return null;
|
|
40
|
+
try {
|
|
41
|
+
return parseStoredStreamTailSequence(decode(bytes));
|
|
42
|
+
} catch {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|