@lostgradient/weft 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +79 -24
- package/dist/cli/conformance.js +7 -1
- package/dist/cli/generated/operation-client.generated.d.ts +28 -13
- package/dist/cli/generated/operation-client.generated.js +1 -0
- package/dist/cli/help-text.d.ts +1 -1
- package/dist/cli/help-text.js +1 -0
- package/dist/cli/operation-catalog-snapshot.d.ts +8 -0
- package/dist/cli/operation-catalog-snapshot.js +11 -0
- package/dist/cli/parse-schedule-arguments.js +3 -1
- package/dist/cli/schedule.js +2 -1
- package/dist/cli/types.d.ts +1 -0
- package/dist/cli-main.js +79 -78
- package/dist/client/handle-delegation.d.ts +3 -2
- package/dist/client/handle-delegation.js +3 -1
- package/dist/client/http-client-requests.d.ts +2 -1
- package/dist/client/http-client-requests.js +7 -0
- package/dist/client/http-client.d.ts +9 -6
- package/dist/client/http-client.js +10 -1
- package/dist/client/http-request.d.ts +11 -1
- package/dist/client/http-request.js +17 -7
- package/dist/client/index.d.ts +1 -1
- package/dist/client/interface.d.ts +46 -5
- package/dist/client/local.d.ts +4 -1
- package/dist/client/local.js +12 -4
- package/dist/client/start-body.d.ts +4 -3
- package/dist/core/byte-arrays.d.ts +5 -0
- package/dist/core/byte-arrays.js +5 -0
- package/dist/core/checkpoint/lifecycle.d.ts +3 -0
- package/dist/core/checkpoint/lifecycle.js +9 -4
- package/dist/core/checkpoint/serialization.js +12 -5
- package/dist/core/codec/extension-codec.d.ts +16 -0
- package/dist/core/codec/extension-codec.js +100 -6
- package/dist/core/context/activity-retry-state.d.ts +38 -0
- package/dist/core/context/activity-retry-state.js +89 -0
- package/dist/core/context/activity-schedule-to-close.d.ts +159 -0
- package/dist/core/context/activity-schedule-to-close.js +69 -0
- package/dist/core/context/child-workflow-pipe.d.ts +5 -5
- package/dist/core/context/child-workflow-pipe.js +15 -2
- package/dist/core/context/context-presence.d.ts +19 -0
- package/dist/core/context/context-presence.js +13 -0
- package/dist/core/context/durable-operations.d.ts +25 -0
- package/dist/core/context/durable-operations.js +64 -0
- package/dist/core/context/index.d.ts +9 -5
- package/dist/core/context/index.js +17 -12
- package/dist/core/context/internals.d.ts +20 -0
- package/dist/core/context/internals.js +3 -1
- package/dist/core/context/operation-request.d.ts +35 -0
- package/dist/core/context/parallel-cache-entry.d.ts +14 -5
- package/dist/core/context/run-operation.d.ts +6 -1
- package/dist/core/context/run-operation.js +41 -87
- package/dist/core/context/session-state.js +7 -8
- package/dist/core/context/speculative-child.js +2 -0
- package/dist/core/context/types.d.ts +15 -0
- package/dist/core/context/version-patching.d.ts +8 -0
- package/dist/core/context/version-patching.js +40 -0
- package/dist/core/context/workflow-logger.d.ts +98 -0
- package/dist/core/context/workflow-logger.js +68 -0
- package/dist/core/engine/activity-heartbeat-tracking.d.ts +64 -0
- package/dist/core/engine/activity-heartbeat-tracking.js +42 -0
- package/dist/core/engine/activity-per-attempt-timeout.d.ts +41 -0
- package/dist/core/engine/activity-per-attempt-timeout.js +36 -0
- package/dist/core/engine/activity-reconciliation.d.ts +1 -0
- package/dist/core/engine/activity-reconciliation.js +12 -1
- package/dist/core/engine/activity-resolution.d.ts +23 -0
- package/dist/core/engine/activity-resolution.js +37 -0
- package/dist/core/engine/aggregate.js +66 -30
- package/dist/core/engine/async-activity-completion.d.ts +23 -6
- package/dist/core/engine/async-activity-completion.js +53 -12
- package/dist/core/engine/attributes-tags.js +9 -4
- package/dist/core/engine/bulk-operations-purge.d.ts +26 -0
- package/dist/core/engine/bulk-operations-purge.js +38 -3
- package/dist/core/engine/bulk-operations-shared.d.ts +2 -0
- package/dist/core/engine/bulk-operations-shared.js +8 -2
- package/dist/core/engine/bulk-operations.d.ts +4 -1
- package/dist/core/engine/bulk-operations.js +235 -24
- package/dist/core/engine/callback-creators-bundles.d.ts +9 -0
- package/dist/core/engine/callback-creators-bundles.js +30 -2
- package/dist/core/engine/callback-creators-core.js +6 -4
- package/dist/core/engine/callback-creators-router.js +10 -0
- package/dist/core/engine/callback-creators-schedule.d.ts +2 -2
- package/dist/core/engine/callback-creators-schedule.js +12 -8
- package/dist/core/engine/candidate-read-batching.d.ts +6 -0
- package/dist/core/engine/candidate-read-batching.js +1 -0
- package/dist/core/engine/checkpoint-io.js +61 -25
- package/dist/core/engine/checkpoint-reads.js +3 -2
- package/dist/core/engine/checkpoint-replay.d.ts +20 -0
- package/dist/core/engine/checkpoint-replay.js +242 -0
- package/dist/core/engine/checkpoint-side-effects.d.ts +23 -0
- package/dist/core/engine/checkpoint-side-effects.js +35 -0
- package/dist/core/engine/child-workflow-cancellation.d.ts +10 -0
- package/dist/core/engine/child-workflow-cancellation.js +40 -0
- package/dist/core/engine/child-workflow.js +27 -4
- package/dist/core/engine/condition-waiters.d.ts +14 -0
- package/dist/core/engine/condition-waiters.js +5 -0
- package/dist/core/engine/construction.d.ts +3 -0
- package/dist/core/engine/construction.js +21 -8
- package/dist/core/engine/coordination-branch-executors.d.ts +70 -0
- package/dist/core/engine/coordination-branch-executors.js +107 -0
- package/dist/core/engine/deferred-consume-envelope.d.ts +59 -0
- package/dist/core/engine/deferred-consume-envelope.js +14 -0
- package/dist/core/engine/disposal.js +13 -0
- package/dist/core/engine/engine-create-types.d.ts +14 -4
- package/dist/core/engine/engine-internal-types.d.ts +26 -3
- package/dist/core/engine/errors.d.ts +47 -0
- package/dist/core/engine/errors.js +20 -0
- package/dist/core/engine/event-log-compaction.d.ts +8 -0
- package/dist/core/engine/event-log-compaction.js +20 -2
- package/dist/core/engine/fenced-write.d.ts +65 -0
- package/dist/core/engine/fenced-write.js +71 -0
- package/dist/core/engine/finalizer-state.d.ts +28 -0
- package/dist/core/engine/finalizer-state.js +16 -0
- package/dist/core/engine/handles.d.ts +8 -0
- package/dist/core/engine/index.d.ts +34 -16
- package/dist/core/engine/index.js +133 -8
- package/dist/core/engine/inline-parking.js +3 -2
- package/dist/core/engine/internals.d.ts +107 -3
- package/dist/core/engine/lease-codec.d.ts +35 -0
- package/dist/core/engine/lease-codec.js +32 -0
- package/dist/core/engine/lease-deposition.d.ts +66 -0
- package/dist/core/engine/lease-deposition.js +10 -0
- package/dist/core/engine/lease-errors.d.ts +99 -0
- package/dist/core/engine/lease-errors.js +30 -0
- package/dist/core/engine/lease-manager.d.ts +114 -0
- package/dist/core/engine/lease-manager.js +135 -0
- package/dist/core/engine/lifecycle/persist.js +10 -32
- package/dist/core/engine/lifecycle/recovered-services.d.ts +8 -6
- package/dist/core/engine/lifecycle/recovered-services.js +18 -3
- package/dist/core/engine/lifecycle/resume.js +16 -9
- package/dist/core/engine/lifecycle/shared.d.ts +8 -1
- package/dist/core/engine/lifecycle/start-batch.d.ts +1 -1
- package/dist/core/engine/lifecycle/start-batch.js +2 -1
- package/dist/core/engine/lifecycle/start-commit.d.ts +9 -0
- package/dist/core/engine/lifecycle/start-commit.js +50 -8
- package/dist/core/engine/lifecycle/start-or-signal-create.d.ts +58 -0
- package/dist/core/engine/lifecycle/start-or-signal-create.js +95 -0
- package/dist/core/engine/lifecycle/start-or-signal.d.ts +3 -2
- package/dist/core/engine/lifecycle/start-or-signal.js +11 -81
- package/dist/core/engine/lifecycle/start-terminal-conflict-purge.d.ts +39 -0
- package/dist/core/engine/lifecycle/start-terminal-conflict-purge.js +28 -0
- package/dist/core/engine/lifecycle/start.d.ts +4 -4
- package/dist/core/engine/lifecycle/start.js +17 -9
- package/dist/core/engine/lifecycle/transition.js +17 -5
- package/dist/core/engine/lifecycle.d.ts +1 -1
- package/dist/core/engine/list-candidate-resolution.js +2 -2
- package/dist/core/engine/listing.js +9 -5
- package/dist/core/engine/operations-activity.d.ts +4 -11
- package/dist/core/engine/operations-activity.js +22 -49
- package/dist/core/engine/operations-coordination.d.ts +10 -0
- package/dist/core/engine/operations-coordination.js +43 -8
- package/dist/core/engine/operations-router.d.ts +6 -0
- package/dist/core/engine/operations-router.js +2 -0
- package/dist/core/engine/operations-speculate.js +6 -2
- package/dist/core/engine/operations-stream.js +12 -2
- package/dist/core/engine/operations-time.d.ts +4 -2
- package/dist/core/engine/operations-time.js +14 -2
- package/dist/core/engine/operations-wait-condition.d.ts +23 -0
- package/dist/core/engine/operations-wait-condition.js +62 -0
- package/dist/core/engine/ownership-options.d.ts +23 -0
- package/dist/core/engine/ownership-options.js +26 -0
- package/dist/core/engine/payload-size-policy.d.ts +3 -0
- package/dist/core/engine/payload-size-policy.js +4 -0
- package/dist/core/engine/pending-updates.d.ts +17 -0
- package/dist/core/engine/pending-updates.js +33 -11
- package/dist/core/engine/queries.js +1 -1
- package/dist/core/engine/registration.d.ts +1 -0
- package/dist/core/engine/registration.js +18 -3
- package/dist/core/engine/schedule-jitter.d.ts +5 -0
- package/dist/core/engine/schedule-jitter.js +10 -0
- package/dist/core/engine/schedule-run.d.ts +17 -0
- package/dist/core/engine/schedule-run.js +38 -0
- package/dist/core/engine/schedule-timer.js +81 -17
- package/dist/core/engine/schedules.d.ts +7 -4
- package/dist/core/engine/schedules.js +37 -16
- package/dist/core/engine/search-attribute-records.d.ts +4 -0
- package/dist/core/engine/search-attribute-records.js +17 -0
- package/dist/core/engine/signals.d.ts +18 -2
- package/dist/core/engine/signals.js +42 -21
- package/dist/core/engine/state-utilities.d.ts +49 -2
- package/dist/core/engine/state-utilities.js +114 -3
- package/dist/core/engine/storage-io.d.ts +16 -2
- package/dist/core/engine/storage-io.js +26 -5
- package/dist/core/engine/stream-chunk-loading.d.ts +2 -0
- package/dist/core/engine/stream-chunk-loading.js +24 -1
- package/dist/core/engine/sub-operation.js +22 -3
- package/dist/core/engine/termination/cleanup.d.ts +3 -1
- package/dist/core/engine/termination/cleanup.js +25 -1
- package/dist/core/engine/termination/complete.js +44 -6
- package/dist/core/engine/termination/finalizer-activity.d.ts +53 -0
- package/dist/core/engine/termination/finalizer-activity.js +30 -0
- package/dist/core/engine/termination/finalizer-claim.d.ts +110 -0
- package/dist/core/engine/termination/finalizer-claim.js +80 -0
- package/dist/core/engine/termination/finalizer.d.ts +48 -0
- package/dist/core/engine/termination/finalizer.js +159 -0
- package/dist/core/engine/termination/suspend.d.ts +3 -1
- package/dist/core/engine/termination.d.ts +1 -0
- package/dist/core/engine/termination.js +4 -0
- package/dist/core/engine/updates.js +5 -25
- package/dist/core/engine/validation/schedule.d.ts +2 -1
- package/dist/core/engine/validation/schedule.js +51 -2
- package/dist/core/engine/validation.js +32 -5
- package/dist/core/engine/waiting-update-response.d.ts +8 -0
- package/dist/core/engine/waiting-update-response.js +22 -0
- package/dist/core/engine/workflow-concurrency.d.ts +10 -0
- package/dist/core/engine/workflow-concurrency.js +136 -0
- package/dist/core/engine/workflow-feed.d.ts +4 -5
- package/dist/core/engine/workflow-feed.js +4 -1
- package/dist/core/engine/workflow-indexes.d.ts +9 -0
- package/dist/core/engine/workflow-indexes.js +10 -0
- package/dist/core/engine/workflow-state-stream.js +33 -13
- package/dist/core/engine/workflow-visibility-queries.d.ts +2 -2
- package/dist/core/engine-helpers.js +1 -0
- package/dist/core/events/activity-events.d.ts +43 -12
- package/dist/core/events/activity-events.js +28 -0
- package/dist/core/events/attribute-events.d.ts +2 -3
- package/dist/core/events/event-map.d.ts +18 -12
- package/dist/core/events/index.d.ts +1 -0
- package/dist/core/events/index.js +1 -0
- package/dist/core/events/schedule-events.d.ts +71 -0
- package/dist/core/events/schedule-events.js +29 -0
- package/dist/core/events/signal-events.d.ts +4 -6
- package/dist/core/events/system-events.d.ts +29 -19
- package/dist/core/events/system-events.js +26 -0
- package/dist/core/events/update-events.d.ts +6 -8
- package/dist/core/events/workflow-events.d.ts +88 -23
- package/dist/core/events/workflow-events.js +26 -0
- package/dist/core/failure-categories.js +5 -17
- package/dist/core/fault-code.d.ts +9 -3
- package/dist/core/fault-code.js +1 -0
- package/dist/core/inline-execution-strategy.context-options.d.ts +69 -0
- package/dist/core/inline-execution-strategy.context-options.js +56 -0
- package/dist/core/inline-execution-strategy.d.ts +31 -36
- package/dist/core/inline-execution-strategy.js +16 -27
- package/dist/core/list-filter-validation.d.ts +1 -1
- package/dist/core/payload-size.d.ts +1 -1
- package/dist/core/persisted-data-incompatible-error.d.ts +9 -7
- package/dist/core/review/events.d.ts +6 -8
- package/dist/core/scheduler/scheduler-class.d.ts +10 -1
- package/dist/core/scheduler/scheduler-class.js +38 -11
- package/dist/core/scheduler/timer-batch.js +9 -1
- package/dist/core/scheduler/timer-sources.d.ts +1 -0
- package/dist/core/scheduler/timer-sources.js +11 -5
- package/dist/core/session-state.d.ts +0 -1
- package/dist/core/session-state.js +2 -2
- package/dist/core/start-workflow-validation.d.ts +34 -0
- package/dist/core/start-workflow-validation.js +19 -0
- package/dist/core/types/activity-verification.d.ts +67 -0
- package/dist/core/types/activity-verification.js +0 -0
- package/dist/core/types/activity.d.ts +80 -61
- package/dist/core/types/bulk.d.ts +50 -9
- package/dist/core/types/checkpoint.d.ts +44 -8
- package/dist/core/types/list-options.d.ts +146 -0
- package/dist/core/types/list-options.js +0 -0
- package/dist/core/types/options.d.ts +121 -165
- package/dist/core/types/schedules.d.ts +39 -3
- package/dist/core/types/services-resolution.d.ts +2 -2
- package/dist/core/types/workflow-builder-runtime.d.ts +12 -3
- package/dist/core/types/workflow-builder-runtime.js +11 -2
- package/dist/core/types/workflow-builder.d.ts +42 -11
- package/dist/core/types/workflow-concurrency.d.ts +39 -0
- package/dist/core/types/workflow-concurrency.js +0 -0
- package/dist/core/types/workflow-context.d.ts +157 -14
- package/dist/core/types/workflow-definition.d.ts +53 -10
- package/dist/core/types/workflow-function.d.ts +84 -9
- package/dist/core/types/workflow-log.d.ts +98 -0
- package/dist/core/types/workflow-log.js +0 -0
- package/dist/core/types/workflow-registries.d.ts +14 -3
- package/dist/core/types/workflow-registry.d.ts +3 -0
- package/dist/core/types.d.ts +4 -0
- package/dist/core/types.js +4 -0
- package/dist/core/versioning.d.ts +9 -39
- package/dist/core/versioning.js +2 -12
- package/dist/core/weft-error.d.ts +44 -1
- package/dist/core/weft-error.js +16 -0
- package/dist/core/worker-execution-strategy-options.d.ts +26 -0
- package/dist/core/worker-execution-strategy.js +40 -36
- package/dist/core/worker-inbound-message.d.ts +38 -0
- package/dist/core/worker-inbound-message.js +37 -0
- package/dist/core/worker-log-abuse-counter.d.ts +175 -0
- package/dist/core/worker-log-abuse-counter.js +107 -0
- package/dist/core/worker-message-helpers.d.ts +47 -0
- package/dist/core/worker-message-helpers.js +26 -0
- package/dist/core/worker-protocol-guard.js +1 -1
- package/dist/core/worker-protocol-log.d.ts +56 -0
- package/dist/core/worker-protocol-log.js +18 -0
- package/dist/core/worker-protocol.d.ts +23 -0
- package/dist/core/worker-protocol.js +12 -2
- package/dist/core/workflow-version-tuple.d.ts +3 -9
- package/dist/core/workflow-version-tuple.js +2 -3
- package/dist/diagnostics/format.js +1 -6
- package/dist/diagnostics/types.d.ts +4 -5
- package/dist/diagnostics/validate.d.ts +0 -1
- package/dist/diagnostics/version-check.d.ts +1 -1
- package/dist/diagnostics/version-check.js +4 -9
- package/dist/index.d.ts +12 -10
- package/dist/index.js +29 -3
- package/dist/json-schema.js +3 -3
- package/dist/mcp/cli.js +27 -27
- package/dist/mcp/dispatcher.js +1 -1
- package/dist/mcp/http.js +16 -6
- package/dist/mcp/protocol.d.ts +2 -0
- package/dist/mcp/protocol.js +1 -1
- package/dist/mcp/session.d.ts +16 -0
- package/dist/mcp/session.js +59 -6
- package/dist/mcp/tools.js +73 -6
- package/dist/observability/index.js +2 -2
- package/dist/server/asyncapi-channels.js +5 -2
- package/dist/server/attribute-filters.d.ts +8 -3
- package/dist/server/attribute-filters.js +6 -1
- package/dist/server/authentication/api-key.d.ts +2 -1
- package/dist/server/authentication/api-key.js +5 -2
- package/dist/server/authentication/constant-time-api-key.d.ts +15 -0
- package/dist/server/authentication/constant-time-api-key.js +24 -0
- package/dist/server/authentication/index.d.ts +1 -1
- package/dist/server/authentication/index.js +7 -4
- package/dist/server/authentication/rotating-api-key-store.d.ts +5 -3
- package/dist/server/authentication/rotating-api-key-store.js +19 -11
- package/dist/server/engine-event-feed-backend.d.ts +4 -5
- package/dist/server/fault-to-http.js +8 -1
- package/dist/server/fault-to-json-rpc.js +1 -0
- package/dist/server/fleet-event-feed.d.ts +31 -0
- package/dist/server/fleet-event-feed.js +157 -0
- package/dist/server/handler/index.js +1 -1
- package/dist/server/handler/response-helpers.js +2 -1
- package/dist/server/handler/route-dispatch.d.ts +6 -3
- package/dist/server/handler/route-dispatch.js +2 -2
- package/dist/server/handler.js +23 -23
- package/dist/server/index.d.ts +32 -2
- package/dist/server/index.js +26 -26
- package/dist/server/json-rpc-transport-helpers.d.ts +1 -0
- package/dist/server/json-rpc-transport-helpers.js +2 -1
- package/dist/server/json-rpc-websocket-runtime.d.ts +11 -2
- package/dist/server/json-rpc-websocket-runtime.js +1 -0
- package/dist/server/json-rpc-websocket-subscriptions.d.ts +10 -0
- package/dist/server/json-rpc-websocket-subscriptions.js +29 -0
- package/dist/server/json-rpc-websocket-types.d.ts +22 -0
- package/dist/server/json-rpc-websocket-types.js +0 -0
- package/dist/server/json-rpc-websocket-validation.js +20 -4
- package/dist/server/json-rpc-websocket.d.ts +2 -43
- package/dist/server/json-rpc-websocket.js +57 -74
- package/dist/server/openapi.d.ts +2 -1
- package/dist/server/openapi.js +1 -3
- package/dist/server/openrpc-document-schema.d.ts +78 -0
- package/dist/server/openrpc-document-schema.js +27 -1
- package/dist/server/openrpc-errors.d.ts +3 -0
- package/dist/server/openrpc-errors.js +2 -1
- package/dist/server/openrpc.js +32 -0
- package/dist/server/operation-catalog/index.d.ts +1 -1
- package/dist/server/operation-catalog/pipeline-helpers.js +1 -0
- package/dist/server/operation-catalog/pipeline-stages.js +26 -12
- package/dist/server/operation-catalog/pipeline.js +8 -1
- package/dist/server/operation-catalog/registry.js +13 -0
- package/dist/server/operation-catalog/types.d.ts +20 -9
- package/dist/server/operation-fault.d.ts +10 -0
- package/dist/server/operation-fault.js +2 -0
- package/dist/server/operation-registry.d.ts +12 -11
- package/dist/server/operation-registry.js +12 -3
- package/dist/server/operations/aggregate-workflows.d.ts +15 -15
- package/dist/server/operations/async-activity.d.ts +2 -2
- package/dist/server/operations/async-activity.js +12 -7
- package/dist/server/operations/bulk-cancel-workflows.d.ts +1 -1
- package/dist/server/operations/bulk-cancel-workflows.js +2 -2
- package/dist/server/operations/bulk-delete-workflows.d.ts +1 -1
- package/dist/server/operations/bulk-delete-workflows.js +2 -2
- package/dist/server/operations/bulk-filter-helpers.d.ts +8 -6
- package/dist/server/operations/bulk-filter-helpers.js +54 -24
- package/dist/server/operations/bulk-mutate-workflow-tags.d.ts +11 -9
- package/dist/server/operations/bulk-mutate-workflow-tags.js +2 -2
- package/dist/server/operations/bulk-operation-helpers.d.ts +2 -2
- package/dist/server/operations/bulk-retry-failed-workflows.d.ts +7 -0
- package/dist/server/operations/bulk-retry-failed-workflows.js +64 -0
- package/dist/server/operations/bulk-signal-workflows.d.ts +11 -9
- package/dist/server/operations/bulk-signal-workflows.js +2 -2
- package/dist/server/operations/cancel-schedule.d.ts +1 -1
- package/dist/server/operations/create-schedule.d.ts +3 -1
- package/dist/server/operations/create-schedule.js +29 -11
- package/dist/server/operations/fleet-events-subscription.d.ts +54 -0
- package/dist/server/operations/fleet-events-subscription.js +99 -0
- package/dist/server/operations/fork-workflow.d.ts +1 -1
- package/dist/server/operations/fork-workflow.js +3 -2
- package/dist/server/operations/get-checkpoint-at.d.ts +1 -1
- package/dist/server/operations/get-registry.d.ts +1 -1
- package/dist/server/operations/get-retention-overview.d.ts +1 -1
- package/dist/server/operations/get-review.d.ts +1 -1
- package/dist/server/operations/get-schedule.d.ts +1 -1
- package/dist/server/operations/get-stream-chunks.d.ts +1 -1
- package/dist/server/operations/get-system-metrics.d.ts +2 -2
- package/dist/server/operations/get-task-diagnostics.d.ts +45 -6
- package/dist/server/operations/get-task-diagnostics.js +101 -7
- package/dist/server/operations/get-update-result.d.ts +1 -1
- package/dist/server/operations/get-workflow-attributes.d.ts +1 -1
- package/dist/server/operations/get-workflow-events.d.ts +1 -1
- package/dist/server/operations/get-workflow-result.d.ts +1 -1
- package/dist/server/operations/get-workflow-timeline.d.ts +1 -1
- package/dist/server/operations/get-workflow.d.ts +1 -1
- package/dist/server/operations/list-checkpoints.d.ts +1 -1
- package/dist/server/operations/list-reviews.d.ts +1 -1
- package/dist/server/operations/list-schedules.d.ts +1 -1
- package/dist/server/operations/list-task-queues.d.ts +2 -2
- package/dist/server/operations/list-workers.d.ts +2 -2
- package/dist/server/operations/list-workflows.d.ts +1 -1
- package/dist/server/operations/operation-helpers.d.ts +16 -1
- package/dist/server/operations/operation-helpers.js +15 -3
- package/dist/server/operations/pause-schedule.d.ts +1 -1
- package/dist/server/operations/purge-workflows.d.ts +5 -5
- package/dist/server/operations/purge-workflows.js +2 -2
- package/dist/server/operations/query-workflow.d.ts +1 -1
- package/dist/server/operations/query-workflow.js +3 -2
- package/dist/server/operations/recover-all.d.ts +1 -1
- package/dist/server/operations/replay-workflow.d.ts +1 -1
- package/dist/server/operations/resume-schedule.d.ts +1 -1
- package/dist/server/operations/set-workflow-attributes.d.ts +1 -1
- package/dist/server/operations/set-workflow-attributes.js +6 -3
- package/dist/server/operations/signal-workflow.js +8 -3
- package/dist/server/operations/single-workflow-tag-mutation.js +13 -3
- package/dist/server/operations/start-or-signal-workflow.d.ts +6 -1
- package/dist/server/operations/start-or-signal-workflow.js +14 -24
- package/dist/server/operations/start-workflow-options.d.ts +6 -0
- package/dist/server/operations/start-workflow-rest-input.d.ts +14 -0
- package/dist/server/operations/start-workflow-rest-input.js +31 -0
- package/dist/server/operations/start-workflow.d.ts +1 -1
- package/dist/server/operations/start-workflow.js +8 -23
- package/dist/server/operations/storage.d.ts +6 -6
- package/dist/server/operations/storage.js +24 -14
- package/dist/server/operations/stream-workflow-sse.d.ts +1 -1
- package/dist/server/operations/submit-review-decision.d.ts +1 -1
- package/dist/server/operations/submit-review-decision.js +6 -3
- package/dist/server/operations/update-schedule.d.ts +1 -1
- package/dist/server/operations/update-schedule.js +7 -4
- package/dist/server/operations/update-workflow.d.ts +1 -1
- package/dist/server/operations/update-workflow.js +7 -3
- package/dist/server/operations/worker-drain.d.ts +8 -8
- package/dist/server/operations/worker-drain.js +11 -8
- package/dist/server/operations/workflow-events-subscription.d.ts +7 -8
- package/dist/server/operations/workflow-events-subscription.js +43 -8
- package/dist/server/rest-binding.d.ts +3 -1
- package/dist/server/rest-bindings.js +12 -0
- package/dist/server/rest-body.d.ts +10 -0
- package/dist/server/rest-body.js +80 -0
- package/dist/server/runtime/authentication-bridge.d.ts +1 -0
- package/dist/server/runtime/authentication-bridge.js +33 -6
- package/dist/server/runtime/client-visible-events.d.ts +3 -0
- package/dist/server/runtime/client-visible-events.js +65 -0
- package/dist/server/runtime/context.d.ts +7 -0
- package/dist/server/runtime/event-broadcasting.d.ts +6 -0
- package/dist/server/runtime/event-broadcasting.js +72 -38
- package/dist/server/runtime/retry.d.ts +1 -0
- package/dist/server/runtime/retry.js +14 -0
- package/dist/server/runtime/shutdown.d.ts +7 -6
- package/dist/server/runtime/shutdown.js +6 -1
- package/dist/server/runtime/task-polling.js +61 -20
- package/dist/server/runtime/task-reconciliation.js +9 -1
- package/dist/server/runtime/task-result-resolution.d.ts +15 -0
- package/dist/server/runtime/task-result-resolution.js +81 -0
- package/dist/server/runtime/websocket-stream.d.ts +20 -1
- package/dist/server/runtime/websocket-stream.js +173 -7
- package/dist/server/runtime/websocket-upgrade.js +22 -3
- package/dist/server/runtime/websocket-worker.d.ts +1 -1
- package/dist/server/runtime/websocket-worker.js +38 -30
- package/dist/server/serve-internals.d.ts +3 -1
- package/dist/server/serve-internals.js +18 -2
- package/dist/server/task-state.d.ts +30 -0
- package/dist/server/task-state.js +28 -0
- package/dist/server/workflow-event-feed.d.ts +36 -115
- package/dist/server/workflow-event-feed.js +92 -27
- package/dist/service-worker/index.js +30 -30
- package/dist/storage/auto.js +1 -1
- package/dist/storage/bun-sql.js +24 -0
- package/dist/storage/compressed-storage.js +1 -1
- package/dist/storage/default-scope.d.ts +7 -4
- package/dist/storage/http.js +2 -2
- package/dist/storage/index.d.ts +76 -4
- package/dist/storage/indexeddb.js +1 -1
- package/dist/storage/interface.d.ts +163 -0
- package/dist/storage/interface.js +1 -1
- package/dist/storage/key-prefixes.d.ts +1 -1
- package/dist/storage/key-prefixes.js +10 -0
- package/dist/storage/lmdb.d.ts +4 -3
- package/dist/storage/lmdb.js +1 -1
- package/dist/storage/memory.js +1 -1
- package/dist/storage/neon-batch.d.ts +30 -0
- package/dist/storage/neon-batch.js +30 -0
- package/dist/storage/neon-value-mapping.d.ts +30 -3
- package/dist/storage/neon-value-mapping.js +12 -0
- package/dist/storage/neon.d.ts +16 -0
- package/dist/storage/neon.js +9 -4
- package/dist/storage/node-sqlite.js +23 -0
- package/dist/storage/postgres-key-value-queries.d.ts +69 -44
- package/dist/storage/postgres-key-value-queries.js +62 -24
- package/dist/storage/resolve.js +1 -1
- package/dist/storage/scoped-storage.js +1 -1
- package/dist/storage/testing.d.ts +168 -0
- package/dist/storage/testing.js +2 -0
- package/dist/storage/turso.d.ts +8 -0
- package/dist/storage/turso.js +2 -2
- package/dist/storage/typed-storage.js +1 -1
- package/dist/storage/web-extension.js +1 -1
- package/dist/testing/index.js +28 -28
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/worker/protocol.js +1 -1
- package/dist/workers/worker-replay-state.d.ts +32 -0
- package/dist/workers/worker-replay-state.js +35 -0
- package/dist/workers/worker-state-namespace.d.ts +21 -0
- package/dist/workers/worker-state-namespace.js +13 -0
- package/dist/workers/workflow-runner.d.ts +19 -15
- package/dist/workers/workflow-runner.js +72 -60
- package/dist/workers/workflow-worker-entry.js +5 -2
- package/package.json +5 -1
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export const WORKFLOW_VERSION_LOCAL_PREFIX = "version:";
|
|
2
|
+
export function resolveWorkflowVersionPatch(checkpointLocals, changeId, minSupported, maxSupported) {
|
|
3
|
+
validateWorkflowVersionPatchArguments(changeId, minSupported, maxSupported);
|
|
4
|
+
const localKey = `${WORKFLOW_VERSION_LOCAL_PREFIX}${changeId}`, existing = checkpointLocals[localKey];
|
|
5
|
+
if (existing === void 0)
|
|
6
|
+
return {
|
|
7
|
+
localKey,
|
|
8
|
+
version: maxSupported,
|
|
9
|
+
newlyPinned: !0,
|
|
10
|
+
checkpointLocals: { ...checkpointLocals, [localKey]: maxSupported }
|
|
11
|
+
};
|
|
12
|
+
if (typeof existing !== "number" || !Number.isSafeInteger(existing))
|
|
13
|
+
throw Error(`Invalid checkpointed workflow version patch "${changeId}" value ${JSON.stringify(existing)}`);
|
|
14
|
+
const version = existing;
|
|
15
|
+
assertPinnedVersionSupported(changeId, version, minSupported, maxSupported);
|
|
16
|
+
return {
|
|
17
|
+
localKey,
|
|
18
|
+
version,
|
|
19
|
+
newlyPinned: !1,
|
|
20
|
+
checkpointLocals
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function validateWorkflowVersionPatchArguments(changeId, minSupported, maxSupported) {
|
|
24
|
+
if (typeof changeId !== "string" || changeId.length === 0)
|
|
25
|
+
throw Error("ctx.getVersion() requires a non-empty changeId");
|
|
26
|
+
assertVersionBoundary("minSupported", minSupported);
|
|
27
|
+
assertVersionBoundary("maxSupported", maxSupported);
|
|
28
|
+
if (minSupported > maxSupported)
|
|
29
|
+
throw Error("ctx.getVersion() minSupported must be less than or equal to maxSupported");
|
|
30
|
+
}
|
|
31
|
+
function assertVersionBoundary(name, value) {
|
|
32
|
+
if (!Number.isSafeInteger(value))
|
|
33
|
+
throw Error(`ctx.getVersion() ${name} must be a safe integer`);
|
|
34
|
+
}
|
|
35
|
+
function assertPinnedVersionSupported(changeId, version, minSupported, maxSupported) {
|
|
36
|
+
if (version < minSupported)
|
|
37
|
+
throw Error(`Workflow version patch "${changeId}" is pinned to version ${version}, below the minimum supported version ${minSupported}`);
|
|
38
|
+
if (version > maxSupported)
|
|
39
|
+
throw Error(`Workflow version patch "${changeId}" is pinned to version ${version}, above the maximum supported version ${maxSupported}`);
|
|
40
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type { WorkflowLogger, WorkflowLogRecord } from '../types/workflow-log.ts';
|
|
2
|
+
import type { ContextInternals } from './internals.ts';
|
|
3
|
+
/**
|
|
4
|
+
* Dispatch one record to the matching `console` method (`debug`/`info`/`warn`/`error`).
|
|
5
|
+
* The single console-fallback primitive: the logger factory uses it when no sink is
|
|
6
|
+
* installed or a sink throws, and the worker-log host-delivery path (#529) uses it when
|
|
7
|
+
* the host `onLog` sink throws — so console-fallback behavior cannot drift between the
|
|
8
|
+
* inline and worker-forwarded paths.
|
|
9
|
+
*/
|
|
10
|
+
export declare function logRecordToConsole(record: WorkflowLogRecord): void;
|
|
11
|
+
/**
|
|
12
|
+
* Inputs the logger needs at construction. The replay/clock probes (`isReplaying`,
|
|
13
|
+
* `now`) are evaluated fresh per emit so they track the live frontier; the identity
|
|
14
|
+
* fields (`workflowId`, `workflowType`) and the `sink` are fixed values.
|
|
15
|
+
*/
|
|
16
|
+
export interface WorkflowLoggerBindings {
|
|
17
|
+
readonly workflowId: string;
|
|
18
|
+
readonly workflowType: string;
|
|
19
|
+
/**
|
|
20
|
+
* Whether the current execution position is a replay of an already-committed
|
|
21
|
+
* step. Evaluated lazily at each emit call so it reflects the live frontier.
|
|
22
|
+
*/
|
|
23
|
+
isReplaying(): boolean;
|
|
24
|
+
/** Wall-clock millisecond timestamp for the record (never checkpointed). */
|
|
25
|
+
now(): number;
|
|
26
|
+
/**
|
|
27
|
+
* Optional host sink (`EngineOptions.onLog`). When provided, each non-replayed
|
|
28
|
+
* record is routed here INSTEAD of the console — the host owns where logs go
|
|
29
|
+
* (pino / winston / OpenTelemetry / etc.). When absent, records fall back to the
|
|
30
|
+
* matching `console` method, preserving the default behavior. `onLog` is fixed at
|
|
31
|
+
* engine construction (it has no public setter), so this is a captured value, not
|
|
32
|
+
* a per-emit resolver.
|
|
33
|
+
*/
|
|
34
|
+
readonly sink?: (record: WorkflowLogRecord) => void;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Create a {@link WorkflowLogger} from the given bindings. Each method suppresses
|
|
38
|
+
* emission when `bindings.isReplaying()` is true (so a recovered run does not
|
|
39
|
+
* re-emit logs from the replayed prefix). A non-replayed record is routed to the
|
|
40
|
+
* host sink (`bindings.sink`) when one is installed, and otherwise to the matching
|
|
41
|
+
* `console` method — so a host that wires `EngineOptions.onLog` takes full control
|
|
42
|
+
* of log routing without duplicate console noise, while the default stays console.
|
|
43
|
+
*
|
|
44
|
+
* A logger must never be able to crash the thing it is logging: if the host sink
|
|
45
|
+
* throws (a serialization error, a transport failure, a bug in the callback — all
|
|
46
|
+
* realistic for the pino / winston / OpenTelemetry integrations this targets), the
|
|
47
|
+
* throw is swallowed and the record falls back to `console` so the workflow run is
|
|
48
|
+
* not marked failed by a logging error.
|
|
49
|
+
*/
|
|
50
|
+
export declare function createWorkflowLogger(bindings: WorkflowLoggerBindings): WorkflowLogger;
|
|
51
|
+
/**
|
|
52
|
+
* Build the inline `ctx.log` logger for a {@link Context}. The replay probe reads
|
|
53
|
+
* the RAW nullable `internals.accumulatedResults` field (not the allocating
|
|
54
|
+
* `ctx.accumulatedResults` getter) and the live `internals.stepIndex` without
|
|
55
|
+
* incrementing it — `ctx.log` consumes no durable position, the same step-neutral
|
|
56
|
+
* peek `waitForSignal` makes. `getInternals` is read per emit so the probe tracks
|
|
57
|
+
* the frontier as durable ops advance `stepIndex`. The `sink` is captured by value:
|
|
58
|
+
* `EngineOptions.onLog` is fixed at engine construction, so it never changes for the
|
|
59
|
+
* life of the context.
|
|
60
|
+
*/
|
|
61
|
+
export declare function createInlineWorkflowLogger(workflowId: string, workflowType: string, getInternals: () => Pick<ContextInternals, 'accumulatedResults' | 'stepIndex' | 'getNow'>, sink?: (record: WorkflowLogRecord) => void): WorkflowLogger;
|
|
62
|
+
/**
|
|
63
|
+
* The slice of worker replay state the worker logger's replay probe reads. A step
|
|
64
|
+
* being replayed is cached in `accumulatedResults` (it succeeded) OR in
|
|
65
|
+
* `failedOutcomes` (it failed and the failure is replayed) — the logger must check
|
|
66
|
+
* both, mirroring the runner's own `hasCachedWorkerOutcome`, or a log at a
|
|
67
|
+
* replayed *failure* position would re-emit on recovery.
|
|
68
|
+
*/
|
|
69
|
+
export interface WorkerLoggerReplayState {
|
|
70
|
+
readonly accumulatedResults: ReadonlyMap<number, unknown>;
|
|
71
|
+
readonly failedOutcomes: ReadonlyMap<number, unknown>;
|
|
72
|
+
readonly nextStepIndex: number;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Build the worker-side `ctx.log` logger. Mirrors {@link createInlineWorkflowLogger}
|
|
76
|
+
* through the shared factory; only the replay probe differs. `nextStepIndex` points
|
|
77
|
+
* at the step the worker generator is about to run, so a cached outcome at that
|
|
78
|
+
* index (success in `accumulatedResults` or failure in `failedOutcomes`) means the
|
|
79
|
+
* step is replaying and its preceding log is suppressed; an uncached index is the
|
|
80
|
+
* live frontier — the same per-position check the inline path makes (and the same
|
|
81
|
+
* union the runner's own replay short-circuit uses). The state is read through
|
|
82
|
+
* `getReplayState` (not captured by value) because the worker registers its replay
|
|
83
|
+
* state *after* the context is built, so the closure must observe the live state at
|
|
84
|
+
* emit time. Worker records use wall-clock `Date.now()` (the worker has no engine
|
|
85
|
+
* clock); the timestamp is observability metadata only, never checkpointed.
|
|
86
|
+
*
|
|
87
|
+
* When the engine host installs an `EngineOptions.onLog` sink, the run/resume message
|
|
88
|
+
* reports `hostHasLogSink: true` and the worker supplies a `forwardToHost` callback
|
|
89
|
+
* here (#529): each non-replayed record is posted back to the host as a `log`
|
|
90
|
+
* protocol message INSTEAD of the worker console, mirroring the inline sink. The
|
|
91
|
+
* callback runs through the shared factory's `sink` slot, so its existing
|
|
92
|
+
* throw-then-console fallback applies — if forwarding is impossible (an oversized or
|
|
93
|
+
* non-cloneable record makes `postMessage` throw), the record falls back to the
|
|
94
|
+
* worker console rather than failing the run. When no host sink exists, `forwardToHost`
|
|
95
|
+
* is omitted and the worker logs to its own console, preserving the default and never
|
|
96
|
+
* losing a log to a no-op host callback.
|
|
97
|
+
*/
|
|
98
|
+
export declare function createWorkerWorkflowLogger(workflowId: string, workflowType: string, getReplayState: () => WorkerLoggerReplayState | undefined, forwardToHost?: (record: WorkflowLogRecord) => void): WorkflowLogger;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
const CONSOLE_METHOD = {
|
|
2
|
+
debug: "debug",
|
|
3
|
+
info: "info",
|
|
4
|
+
warn: "warn",
|
|
5
|
+
error: "error"
|
|
6
|
+
};
|
|
7
|
+
export function logRecordToConsole(record) {
|
|
8
|
+
console[CONSOLE_METHOD[record.level]](record);
|
|
9
|
+
}
|
|
10
|
+
function buildLogRecord(bindings, level, message, attributes) {
|
|
11
|
+
return {
|
|
12
|
+
level,
|
|
13
|
+
message,
|
|
14
|
+
workflowId: bindings.workflowId,
|
|
15
|
+
workflowType: bindings.workflowType,
|
|
16
|
+
timestamp: bindings.now(),
|
|
17
|
+
...attributes !== void 0 && { attributes }
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export function createWorkflowLogger(bindings) {
|
|
21
|
+
const emit = (level, message, attributes) => {
|
|
22
|
+
if (bindings.isReplaying())
|
|
23
|
+
return;
|
|
24
|
+
const record = buildLogRecord(bindings, level, message, attributes);
|
|
25
|
+
if (bindings.sink !== void 0) {
|
|
26
|
+
try {
|
|
27
|
+
bindings.sink(record);
|
|
28
|
+
} catch {
|
|
29
|
+
logRecordToConsole(record);
|
|
30
|
+
}
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
logRecordToConsole(record);
|
|
34
|
+
};
|
|
35
|
+
return {
|
|
36
|
+
debug: (message, attributes) => emit("debug", message, attributes),
|
|
37
|
+
info: (message, attributes) => emit("info", message, attributes),
|
|
38
|
+
warn: (message, attributes) => emit("warn", message, attributes),
|
|
39
|
+
error: (message, attributes) => emit("error", message, attributes)
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
export function createInlineWorkflowLogger(workflowId, workflowType, getInternals, sink) {
|
|
43
|
+
return createWorkflowLogger({
|
|
44
|
+
workflowId,
|
|
45
|
+
workflowType,
|
|
46
|
+
isReplaying: () => {
|
|
47
|
+
const internals = getInternals();
|
|
48
|
+
return internals.accumulatedResults?.has(internals.stepIndex) ?? !1;
|
|
49
|
+
},
|
|
50
|
+
now: () => getInternals().getNow(),
|
|
51
|
+
...sink !== void 0 && { sink }
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
export function createWorkerWorkflowLogger(workflowId, workflowType, getReplayState, forwardToHost) {
|
|
55
|
+
return createWorkflowLogger({
|
|
56
|
+
workflowId,
|
|
57
|
+
workflowType,
|
|
58
|
+
isReplaying: () => {
|
|
59
|
+
const replayState = getReplayState();
|
|
60
|
+
if (replayState === void 0)
|
|
61
|
+
return !1;
|
|
62
|
+
const step = replayState.nextStepIndex;
|
|
63
|
+
return replayState.accumulatedResults.has(step) || replayState.failedOutcomes.has(step);
|
|
64
|
+
},
|
|
65
|
+
now: () => Date.now(),
|
|
66
|
+
...forwardToHost !== void 0 && { sink: forwardToHost }
|
|
67
|
+
});
|
|
68
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { ActivityContext } from '../types.ts';
|
|
2
|
+
import type { EngineInternals } from './internals.ts';
|
|
3
|
+
/**
|
|
4
|
+
* Per-step heartbeat tracking for {@link ActivityContext.lastHeartbeatDetails}.
|
|
5
|
+
*
|
|
6
|
+
* The store is keyed `workflowId -> step` (not `workflowId` alone) so a retry of
|
|
7
|
+
* an activity step reads the heartbeat ITS prior attempt recorded — and so a
|
|
8
|
+
* later step's first attempt never inherits an earlier step's heartbeat, and
|
|
9
|
+
* concurrent `ctx.all` activities never clobber one another. The step is stable
|
|
10
|
+
* across retry attempts (assigned once at `stepIndex++`). Held only in engine
|
|
11
|
+
* memory and cleared by workflowId (the outer key) on terminal cleanup and purge.
|
|
12
|
+
*/
|
|
13
|
+
/** Record the heartbeat the current attempt of a step sent. */
|
|
14
|
+
export declare function recordLastHeartbeatForStep(internals: EngineInternals, workflowId: string, step: number, details: unknown): void;
|
|
15
|
+
/** Read the heartbeat a prior attempt of this step recorded, or `undefined`. */
|
|
16
|
+
export declare function readLastHeartbeatForStep(internals: EngineInternals, workflowId: string, step: number): unknown;
|
|
17
|
+
/**
|
|
18
|
+
* Drop the heartbeat tracked for a single step once that step has completed
|
|
19
|
+
* successfully — after inline verify, and (on the idempotency path) after the
|
|
20
|
+
* reconciliation write, so a verify-rejection retry still reads its prior
|
|
21
|
+
* attempt's heartbeat. The plain path has no reconciliation write; both paths
|
|
22
|
+
* call this only at their successful return. Removes the inner-map entry and
|
|
23
|
+
* drops the outer workflow entry when its last step clears, so a long-lived
|
|
24
|
+
* workflow doesn't accumulate stale per-step heartbeats. Clearing late is
|
|
25
|
+
* harmless (bounded by terminal cleanup); clearing early would strip the
|
|
26
|
+
* resumable-batch heartbeat a retry depends on, so this is only ever called from
|
|
27
|
+
* the non-speculative success path.
|
|
28
|
+
*/
|
|
29
|
+
export declare function clearLastHeartbeatForStep(internals: EngineInternals, workflowId: string, step: number): void;
|
|
30
|
+
/**
|
|
31
|
+
* #493: in development mode, emit a COARSE warning when an inline activity RETRY
|
|
32
|
+
* (`attempt > 1`) starts with no `lastHeartbeatDetails` — the closest runtime
|
|
33
|
+
* proxy for the resumable-batch footgun. We cannot distinguish "the prior attempt
|
|
34
|
+
* never heartbeated" (benign) from "the heartbeat was discarded by a process
|
|
35
|
+
* restart" (the dangerous case): the distinguishing fact is the wiped in-memory
|
|
36
|
+
* state, gone by definition. So the message names BOTH possibilities and never
|
|
37
|
+
* claims a restart happened. The gates (development, inline, attempt, missing
|
|
38
|
+
* heartbeat) are read straight off the code below; two facts are NOT derivable
|
|
39
|
+
* from it:
|
|
40
|
+
*
|
|
41
|
+
* - It fires on the speculative path too. A speculative `attempt > 1` that later
|
|
42
|
+
* rolls back still ran twice and still lost any resume payload, so the footgun
|
|
43
|
+
* is real regardless — letting it warn is the deliberate, honest choice.
|
|
44
|
+
* - It pairs with {@link clearLastHeartbeatForStep} without interference: the
|
|
45
|
+
* clear fires only on SUCCESS (a step that never retries) and this reads
|
|
46
|
+
* `undefined` only on a RETRY, and a cleared step is a completed step that by
|
|
47
|
+
* definition will not be retried.
|
|
48
|
+
*
|
|
49
|
+
* The inline gate keys on `!activityWorkerDispatcher` because dispatch is
|
|
50
|
+
* engine-wide today; the heartbeat cache is only ever written on the inline path,
|
|
51
|
+
* so whenever a dispatcher exists the cache is structurally empty and the gate is
|
|
52
|
+
* required to suppress a false warning on every worker retry. A future per-activity
|
|
53
|
+
* routing model would need this gate to key on the resolved per-dispatch mode
|
|
54
|
+
* instead.
|
|
55
|
+
*/
|
|
56
|
+
export declare function warnIfRetryMissingHeartbeat(internals: EngineInternals, workflowId: string, step: number, attempt: number): void;
|
|
57
|
+
/**
|
|
58
|
+
* Build the {@link ActivityContext} handed to an inline activity function. The
|
|
59
|
+
* signal comes from the per-workflow AbortController (so workflow cancellation
|
|
60
|
+
* aborts it); `lastHeartbeatDetails` and `heartbeat` are wired to the per-step
|
|
61
|
+
* tracking above; `completeAsync` is supplied by the caller (it owns the
|
|
62
|
+
* async-completion token machinery).
|
|
63
|
+
*/
|
|
64
|
+
export declare function buildActivityContext(internals: EngineInternals, workflowId: string, step: number, signal: AbortSignal, completeAsync: () => never): ActivityContext;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { DevelopmentWarningEvent } from "../events.js";
|
|
2
|
+
export function recordLastHeartbeatForStep(internals, workflowId, step, details) {
|
|
3
|
+
let byStep = internals.lastHeartbeatDetailsByStep.get(workflowId);
|
|
4
|
+
if (byStep === void 0) {
|
|
5
|
+
byStep = new Map;
|
|
6
|
+
internals.lastHeartbeatDetailsByStep.set(workflowId, byStep);
|
|
7
|
+
}
|
|
8
|
+
byStep.set(step, details);
|
|
9
|
+
}
|
|
10
|
+
export function readLastHeartbeatForStep(internals, workflowId, step) {
|
|
11
|
+
return internals.lastHeartbeatDetailsByStep.get(workflowId)?.get(step);
|
|
12
|
+
}
|
|
13
|
+
export function clearLastHeartbeatForStep(internals, workflowId, step) {
|
|
14
|
+
const byStep = internals.lastHeartbeatDetailsByStep.get(workflowId);
|
|
15
|
+
if (byStep === void 0)
|
|
16
|
+
return;
|
|
17
|
+
byStep.delete(step);
|
|
18
|
+
if (byStep.size === 0)
|
|
19
|
+
internals.lastHeartbeatDetailsByStep.delete(workflowId);
|
|
20
|
+
}
|
|
21
|
+
export function warnIfRetryMissingHeartbeat(internals, workflowId, step, attempt) {
|
|
22
|
+
if (!internals.options.development)
|
|
23
|
+
return;
|
|
24
|
+
if (internals.activityWorkerDispatcher)
|
|
25
|
+
return;
|
|
26
|
+
if (attempt <= 1)
|
|
27
|
+
return;
|
|
28
|
+
if (readLastHeartbeatForStep(internals, workflowId, step) !== void 0)
|
|
29
|
+
return;
|
|
30
|
+
internals.engine.dispatchEvent(new DevelopmentWarningEvent(workflowId, `Activity retry (attempt ${attempt}) at step ${step} has no lastHeartbeatDetails. Either the previous attempt never recorded heartbeat details (it never called heartbeat(), or called it with no details), or the engine process restarted and discarded the in-memory heartbeat (it is not durable). The resumable-batch pattern only resumes across in-process retries; design the activity to restart cleanly when lastHeartbeatDetails is undefined.`, [`step.${step}.lastHeartbeatDetails`]));
|
|
31
|
+
}
|
|
32
|
+
export function buildActivityContext(internals, workflowId, step, signal, completeAsync) {
|
|
33
|
+
return {
|
|
34
|
+
signal,
|
|
35
|
+
lastHeartbeatDetails: readLastHeartbeatForStep(internals, workflowId, step),
|
|
36
|
+
heartbeat: (details) => {
|
|
37
|
+
internals.heartbeatDetails.set(workflowId, details);
|
|
38
|
+
recordLastHeartbeatForStep(internals, workflowId, step, details);
|
|
39
|
+
},
|
|
40
|
+
completeAsync
|
|
41
|
+
};
|
|
42
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { ContextOperationRequest } from '../context.ts';
|
|
2
|
+
import type { EngineInternals } from './internals.ts';
|
|
3
|
+
type ActivityOperation = Extract<ContextOperationRequest, {
|
|
4
|
+
type: 'activity';
|
|
5
|
+
}>;
|
|
6
|
+
/**
|
|
7
|
+
* Resolve the per-attempt `timeout` setup for an activity attempt (#494).
|
|
8
|
+
*
|
|
9
|
+
* The cap is INLINE-only: worker-mode per-attempt bounds are governed by
|
|
10
|
+
* `visibilityTimeout`, and racing the engine's await against a deadline while a
|
|
11
|
+
* remote worker keeps running would orphan its result and risk double-execution on
|
|
12
|
+
* the next visibility-timeout re-dispatch. When a cap is configured, a fresh
|
|
13
|
+
* per-attempt `AbortController` drives cooperative cancellation; its signal is
|
|
14
|
+
* composited with the workflow-wide signal so the activity's `ctx.signal` aborts on
|
|
15
|
+
* EITHER workflow cancellation OR a per-attempt timeout — without the timeout
|
|
16
|
+
* reaching back to cancel the whole workflow (which would also poison the next
|
|
17
|
+
* retry's signal).
|
|
18
|
+
*/
|
|
19
|
+
export declare function resolvePerAttemptTimeout(internals: EngineInternals, workflowId: string, operation: ActivityOperation): {
|
|
20
|
+
perAttemptTimeoutMs: number | undefined;
|
|
21
|
+
attemptAbortController: AbortController | undefined;
|
|
22
|
+
activitySignal: AbortSignal;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Bound a single inline activity attempt by its per-attempt `timeout` (#494).
|
|
26
|
+
*
|
|
27
|
+
* When `timeoutMs` is set and the attempt does not settle first, the returned
|
|
28
|
+
* promise rejects with {@link ActivityPerAttemptTimeoutError} and the per-attempt
|
|
29
|
+
* `AbortController` is aborted with that same error — so the activity's composite
|
|
30
|
+
* `ctx.signal` flips, letting a cooperating activity stop promptly. Weft cannot
|
|
31
|
+
* forcibly preempt the activity function: a non-cooperating activity keeps running
|
|
32
|
+
* in the background until it returns; only the workflow stops awaiting it. The
|
|
33
|
+
* abandoned invocation's eventual settlement is swallowed so it never surfaces as
|
|
34
|
+
* an unhandled rejection after the race has moved on. The timed-out rejection
|
|
35
|
+
* flows through the normal retry path, so a retry policy gets a fresh attempt with
|
|
36
|
+
* a fresh cap (and a fresh per-attempt controller).
|
|
37
|
+
*
|
|
38
|
+
* Returns the invocation unchanged (no timer armed) when no cap is configured.
|
|
39
|
+
*/
|
|
40
|
+
export declare function withPerAttemptTimeout(invocation: unknown, timeoutMs: number | undefined, activityName: string, attempt: number, attemptAbortController: AbortController | undefined): Promise<unknown>;
|
|
41
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ActivityPerAttemptTimeoutError,
|
|
3
|
+
parsePerAttemptTimeoutMs
|
|
4
|
+
} from "../context/activity-schedule-to-close.js";
|
|
5
|
+
export function resolvePerAttemptTimeout(internals, workflowId, operation) {
|
|
6
|
+
const workflowAbortController = internals.inlineStrategy?.getAbortController(workflowId), perAttemptTimeoutMs = internals.activityWorkerDispatcher ? void 0 : parsePerAttemptTimeoutMs(operation.options?.timeout), attemptAbortController = perAttemptTimeoutMs === void 0 ? void 0 : new AbortController, activitySignal = composeActivitySignal(workflowAbortController?.signal, attemptAbortController?.signal);
|
|
7
|
+
return { perAttemptTimeoutMs, attemptAbortController, activitySignal };
|
|
8
|
+
}
|
|
9
|
+
function composeActivitySignal(workflowSignal, attemptSignal) {
|
|
10
|
+
const signals = [workflowSignal, attemptSignal].filter((signal) => signal !== void 0), [first] = signals;
|
|
11
|
+
if (first === void 0)
|
|
12
|
+
return new AbortController().signal;
|
|
13
|
+
if (signals.length === 1)
|
|
14
|
+
return first;
|
|
15
|
+
return AbortSignal.any(signals);
|
|
16
|
+
}
|
|
17
|
+
export async function withPerAttemptTimeout(invocation, timeoutMs, activityName, attempt, attemptAbortController) {
|
|
18
|
+
if (timeoutMs === void 0)
|
|
19
|
+
return invocation;
|
|
20
|
+
const activityPromise = Promise.resolve(invocation);
|
|
21
|
+
activityPromise.catch(() => {});
|
|
22
|
+
let timer;
|
|
23
|
+
const deadline = new Promise((_resolve, reject) => {
|
|
24
|
+
timer = setTimeout(() => {
|
|
25
|
+
const error = new ActivityPerAttemptTimeoutError(activityName, attempt, timeoutMs);
|
|
26
|
+
reject(error);
|
|
27
|
+
attemptAbortController?.abort(error);
|
|
28
|
+
}, timeoutMs);
|
|
29
|
+
});
|
|
30
|
+
try {
|
|
31
|
+
return await Promise.race([activityPromise, deadline]);
|
|
32
|
+
} finally {
|
|
33
|
+
if (timer !== void 0)
|
|
34
|
+
clearTimeout(timer);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -101,6 +101,7 @@ export declare function resolveStartedActivityReconciliationRecord(internals: En
|
|
|
101
101
|
completedResult: unknown;
|
|
102
102
|
}>;
|
|
103
103
|
export declare function writeActivityReconciliationTransition(storage: Storage, reference: ActivityReconciliationReference, expectedRecord: ActivityReconciliationRecord, nextRecord: ActivityReconciliationRecord): Promise<void>;
|
|
104
|
+
export declare function stageActivityReconciliationTransitionWithAtomicWorkflowCommit(internals: EngineInternals, workflowId: string, reference: ActivityReconciliationReference, expectedRecord: ActivityReconciliationRecord, nextRecord: ActivityReconciliationRecord): void;
|
|
104
105
|
export declare function normalizePreDispatchVerificationResult(result: ActivityVerificationResult): 'not-completed' | 'completed-result-unavailable' | 'indeterminate' | {
|
|
105
106
|
result: unknown;
|
|
106
107
|
};
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
import { decode, encode } from "../codec.js";
|
|
7
7
|
import { assertPayloadWithinLimit } from "../payload-size.js";
|
|
8
8
|
import { WeftError } from "../weft-error.js";
|
|
9
|
+
import { stageAtomicWorkflowCommitSideEffects } from "./checkpoint-side-effects.js";
|
|
9
10
|
|
|
10
11
|
export class ActivityReconciliationCapabilityError extends WeftError {
|
|
11
12
|
constructor() {
|
|
@@ -95,9 +96,19 @@ export async function resolveStartedActivityReconciliationRecord(internals, work
|
|
|
95
96
|
return { completedResult: normalized.result };
|
|
96
97
|
}
|
|
97
98
|
export async function writeActivityReconciliationTransition(storage, reference, expectedRecord, nextRecord) {
|
|
98
|
-
|
|
99
|
+
const sideEffects = buildActivityReconciliationTransitionSideEffects(reference, expectedRecord, nextRecord);
|
|
100
|
+
if (!await storageConditionalBatch(storage, sideEffects.conditions, sideEffects.operations))
|
|
99
101
|
throw new ActivityReconciliationConflictError("Activity reconciliation completion lost compare-and-set ownership.");
|
|
100
102
|
}
|
|
103
|
+
export function stageActivityReconciliationTransitionWithAtomicWorkflowCommit(internals, workflowId, reference, expectedRecord, nextRecord) {
|
|
104
|
+
stageAtomicWorkflowCommitSideEffects(internals, workflowId, buildActivityReconciliationTransitionSideEffects(reference, expectedRecord, nextRecord));
|
|
105
|
+
}
|
|
106
|
+
function buildActivityReconciliationTransitionSideEffects(reference, expectedRecord, nextRecord) {
|
|
107
|
+
return {
|
|
108
|
+
conditions: [{ key: reference.key, expectedValue: encode(expectedRecord) }],
|
|
109
|
+
operations: [{ type: "put", key: reference.key, value: encode(nextRecord) }]
|
|
110
|
+
};
|
|
111
|
+
}
|
|
101
112
|
export function normalizePreDispatchVerificationResult(result) {
|
|
102
113
|
if (result === "not-completed")
|
|
103
114
|
return "not-completed";
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ContextOperationRequest } from '../context.ts';
|
|
2
|
+
import type { EngineInternals } from './internals.ts';
|
|
3
|
+
import type { ActivityFunctionWithMetadata } from './operations-activity.ts';
|
|
4
|
+
type ActivityOperation = Extract<ContextOperationRequest, {
|
|
5
|
+
type: 'activity';
|
|
6
|
+
}>;
|
|
7
|
+
/**
|
|
8
|
+
* Resolve the activity callable along with its attached metadata (compensation,
|
|
9
|
+
* verification). Returns `undefined` when no registry and no `operation.fn`
|
|
10
|
+
* resolve the name — the metadata path treats a miss as advisory rather than
|
|
11
|
+
* fatal.
|
|
12
|
+
*/
|
|
13
|
+
export declare function getActivityFunctionWithMetadata(internals: EngineInternals, workflowId: string, operation: ActivityOperation): ActivityFunctionWithMetadata | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* Resolve the activity function for a given operation. Uses the same
|
|
16
|
+
* per-workflow-first-then-global ordering as `getActivityFunctionWithMetadata`.
|
|
17
|
+
* For inline-mode callers that pass an `operation.fn` directly, the registries
|
|
18
|
+
* are still consulted first so a workflow's locally-scoped activity wins over
|
|
19
|
+
* the bare callable. Throws `ActivityResolutionError` when neither path
|
|
20
|
+
* resolves.
|
|
21
|
+
*/
|
|
22
|
+
export declare function resolveActivityFunction(internals: EngineInternals, workflowId: string, operation: ActivityOperation): (...arguments_: unknown[]) => unknown;
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ActivityResolutionError } from "./errors.js";
|
|
2
|
+
function resolveActivityViaRegistries(internals, workflowId, activityName) {
|
|
3
|
+
const workflowType = internals.workflowTypeByWorkflowId.get(workflowId);
|
|
4
|
+
if (workflowType !== void 0) {
|
|
5
|
+
const perWorkflow = internals.activityRegistriesByWorkflow.get(workflowType);
|
|
6
|
+
if (perWorkflow !== void 0) {
|
|
7
|
+
const perWorkflowFn = perWorkflow.resolve(activityName);
|
|
8
|
+
if (perWorkflowFn)
|
|
9
|
+
return { fn: perWorkflowFn, workflowType };
|
|
10
|
+
}
|
|
11
|
+
const globalFn = internals.activityRegistry.resolve(activityName);
|
|
12
|
+
if (globalFn)
|
|
13
|
+
return { fn: globalFn, workflowType };
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const globalFn = internals.activityRegistry.resolve(activityName);
|
|
17
|
+
if (globalFn)
|
|
18
|
+
return { fn: globalFn, workflowType: "<unknown>" };
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
export function getActivityFunctionWithMetadata(internals, workflowId, operation) {
|
|
22
|
+
const resolved = resolveActivityViaRegistries(internals, workflowId, operation.activityName);
|
|
23
|
+
if (resolved)
|
|
24
|
+
return resolved.fn;
|
|
25
|
+
if (typeof operation.fn === "function")
|
|
26
|
+
return operation.fn;
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
export function resolveActivityFunction(internals, workflowId, operation) {
|
|
30
|
+
const resolved = resolveActivityViaRegistries(internals, workflowId, operation.activityName);
|
|
31
|
+
if (resolved)
|
|
32
|
+
return resolved.fn;
|
|
33
|
+
if (operation.fn)
|
|
34
|
+
return operation.fn;
|
|
35
|
+
const workflowType = internals.workflowTypeByWorkflowId.get(workflowId) ?? "<unknown>";
|
|
36
|
+
throw new ActivityResolutionError(workflowType, operation.activityName);
|
|
37
|
+
}
|
|
@@ -5,12 +5,16 @@ import {
|
|
|
5
5
|
MAX_AGGREGATE_DISTINCT_KEYS,
|
|
6
6
|
normalizeAggregateOptions
|
|
7
7
|
} from "../aggregate-validation.js";
|
|
8
|
-
import { decode } from "../codec.js";
|
|
9
8
|
import { normalizeListFilter } from "../list-filter-validation.js";
|
|
10
9
|
import { WeftError } from "../weft-error.js";
|
|
11
10
|
import { normalizeWorkflowTags } from "../workflow-tags.js";
|
|
11
|
+
import { CONSTRAINED_ID_CHUNK_SIZE } from "./candidate-read-batching.js";
|
|
12
12
|
import { resolveListCandidateIds } from "./list-candidate-resolution.js";
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
readSearchAttributesForFilter,
|
|
15
|
+
readSearchAttributesForStates
|
|
16
|
+
} from "./search-attribute-records.js";
|
|
17
|
+
import { decodeSearchAttributeRecord, matchesListFilter } from "./state-utilities.js";
|
|
14
18
|
import { decodeWorkflowState } from "./validation.js";
|
|
15
19
|
import { MAX_LIST_SCAN_ROWS, WorkflowListScanCapExceededError } from "./workflow-indexes.js";
|
|
16
20
|
import { isTopLevelWorkflowStateKey } from "./workflow-state-stream.js";
|
|
@@ -27,19 +31,6 @@ const ATTRIBUTE_VALUE_TO_KEY = (value) => {
|
|
|
27
31
|
return value.join(",");
|
|
28
32
|
return String(value);
|
|
29
33
|
};
|
|
30
|
-
async function resolveDimensionKey(internals, state, groupBy) {
|
|
31
|
-
if (groupBy === "status")
|
|
32
|
-
return state.status;
|
|
33
|
-
if (groupBy === "type")
|
|
34
|
-
return state.type;
|
|
35
|
-
if (groupBy === "failureCategory")
|
|
36
|
-
return state.failureCategory ?? null;
|
|
37
|
-
const attributeBytes = await internals.storage.get(KEYS.attribute(state.id));
|
|
38
|
-
if (!attributeBytes)
|
|
39
|
-
return null;
|
|
40
|
-
const attributes = decode(attributeBytes);
|
|
41
|
-
return ATTRIBUTE_VALUE_TO_KEY(attributes[groupBy.attribute]);
|
|
42
|
-
}
|
|
43
34
|
|
|
44
35
|
export class UnknownAggregateAttributeError extends WeftError {
|
|
45
36
|
attribute;
|
|
@@ -72,8 +63,8 @@ function validateAggregateInputs(internals, filter, options, executionOptions) {
|
|
|
72
63
|
distinctKeyCap: executionOptions.distinctKeyCap ?? MAX_AGGREGATE_DISTINCT_KEYS
|
|
73
64
|
};
|
|
74
65
|
}
|
|
75
|
-
|
|
76
|
-
const
|
|
66
|
+
function accumulateAggregateKey(key, distinctKeyCap, accumulator) {
|
|
67
|
+
const current = accumulator.counts.get(key);
|
|
77
68
|
if (current === void 0) {
|
|
78
69
|
if (accumulator.counts.size >= distinctKeyCap)
|
|
79
70
|
throw new AggregateDistinctKeyCapExceededError(distinctKeyCap);
|
|
@@ -82,32 +73,77 @@ async function accumulateAggregateState(internals, state, groupBy, distinctKeyCa
|
|
|
82
73
|
accumulator.counts.set(key, current + 1);
|
|
83
74
|
accumulator.total += 1;
|
|
84
75
|
}
|
|
76
|
+
async function resolveDimensionKeys(internals, states, groupBy, searchAttributesByWorkflowId = new Map) {
|
|
77
|
+
if (groupBy === "status")
|
|
78
|
+
return states.map((state) => state.status);
|
|
79
|
+
if (groupBy === "type")
|
|
80
|
+
return states.map((state) => state.type);
|
|
81
|
+
if (groupBy === "failureCategory")
|
|
82
|
+
return states.map((state) => state.failureCategory ?? null);
|
|
83
|
+
return resolveAttributeDimensionKeys(internals, states, groupBy, searchAttributesByWorkflowId);
|
|
84
|
+
}
|
|
85
|
+
async function resolveAttributeDimensionKeys(internals, states, groupBy, searchAttributesByWorkflowId) {
|
|
86
|
+
const keys = [];
|
|
87
|
+
for (let start = 0;start < states.length; start += CONSTRAINED_ID_CHUNK_SIZE) {
|
|
88
|
+
const stateChunk = states.slice(start, start + CONSTRAINED_ID_CHUNK_SIZE), statesNeedingReads = stateChunk.filter((state) => !searchAttributesByWorkflowId.has(state.id)), attributeBytesByWorkflowId = new Map;
|
|
89
|
+
await Promise.all(statesNeedingReads.map(async (state) => {
|
|
90
|
+
attributeBytesByWorkflowId.set(state.id, await internals.storage.get(KEYS.attribute(state.id)));
|
|
91
|
+
}));
|
|
92
|
+
for (const state of stateChunk) {
|
|
93
|
+
const attributes = searchAttributesByWorkflowId.has(state.id) ? searchAttributesByWorkflowId.get(state.id) ?? null : decodeSearchAttributeRecord(attributeBytesByWorkflowId.get(state.id) ?? null);
|
|
94
|
+
if (attributes === null) {
|
|
95
|
+
keys.push(null);
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
keys.push(ATTRIBUTE_VALUE_TO_KEY(attributes[groupBy.attribute]));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return keys;
|
|
102
|
+
}
|
|
103
|
+
async function accumulateAggregateStates(internals, states, groupBy, distinctKeyCap, accumulator, searchAttributesByWorkflowId) {
|
|
104
|
+
const dimensionKeys = await resolveDimensionKeys(internals, states, groupBy, searchAttributesByWorkflowId);
|
|
105
|
+
for (const key of dimensionKeys)
|
|
106
|
+
accumulateAggregateKey(key, distinctKeyCap, accumulator);
|
|
107
|
+
}
|
|
85
108
|
async function accumulateFromConstrainedIds(internals, constrainedIds, normalizedFilter, normalizedTagFilters, groupBy, distinctKeyCap, accumulator) {
|
|
86
|
-
|
|
109
|
+
const orderedIds = [...constrainedIds];
|
|
110
|
+
if (orderedIds.length > MAX_LIST_SCAN_ROWS)
|
|
87
111
|
throw new WorkflowListScanCapExceededError(MAX_LIST_SCAN_ROWS);
|
|
88
|
-
for (
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
112
|
+
for (let start = 0;start < orderedIds.length; start += CONSTRAINED_ID_CHUNK_SIZE) {
|
|
113
|
+
const idChunk = orderedIds.slice(start, start + CONSTRAINED_ID_CHUNK_SIZE), stateBytesChunk = await Promise.all(idChunk.map((workflowId) => internals.storage.get(KEYS.workflow(workflowId)))), searchAttributesByWorkflowId = await readSearchAttributesForStates(internals, stateBytesChunk, normalizedFilter), matchingStates = [];
|
|
114
|
+
for (const stateBytes of stateBytesChunk) {
|
|
115
|
+
if (!stateBytes)
|
|
116
|
+
continue;
|
|
117
|
+
const state = decodeWorkflowState(stateBytes);
|
|
118
|
+
if (!matchesListFilter(state, normalizedFilter, constrainedIds, normalizedTagFilters, searchAttributesByWorkflowId.get(state.id) ?? null))
|
|
119
|
+
continue;
|
|
120
|
+
matchingStates.push(state);
|
|
121
|
+
}
|
|
122
|
+
await accumulateAggregateStates(internals, matchingStates, groupBy, distinctKeyCap, accumulator, searchAttributesByWorkflowId);
|
|
96
123
|
}
|
|
97
124
|
}
|
|
98
125
|
async function accumulateFromFullScan(internals, normalizedFilter, normalizedTagFilters, groupBy, distinctKeyCap, accumulator) {
|
|
99
|
-
let scanned = 0;
|
|
126
|
+
let scanned = 0, matchingStates = [], matchingSearchAttributesByWorkflowId = new Map;
|
|
100
127
|
for await (const [storageKey, value] of internals.storage.scan("wf:")) {
|
|
101
128
|
if (!isTopLevelWorkflowStateKey(storageKey))
|
|
102
129
|
continue;
|
|
103
130
|
scanned += 1;
|
|
104
131
|
if (scanned > MAX_LIST_SCAN_ROWS)
|
|
105
132
|
throw new WorkflowListScanCapExceededError(MAX_LIST_SCAN_ROWS);
|
|
106
|
-
const state = decodeWorkflowState(value);
|
|
107
|
-
if (!matchesListFilter(state, normalizedFilter, null, normalizedTagFilters))
|
|
133
|
+
const state = decodeWorkflowState(value), searchAttributes = await readSearchAttributesForFilter(internals, state.id, normalizedFilter);
|
|
134
|
+
if (!matchesListFilter(state, normalizedFilter, null, normalizedTagFilters, searchAttributes))
|
|
108
135
|
continue;
|
|
109
|
-
|
|
136
|
+
matchingStates.push(state);
|
|
137
|
+
if (searchAttributes !== null)
|
|
138
|
+
matchingSearchAttributesByWorkflowId.set(state.id, searchAttributes);
|
|
139
|
+
if (matchingStates.length === CONSTRAINED_ID_CHUNK_SIZE) {
|
|
140
|
+
await accumulateAggregateStates(internals, matchingStates, groupBy, distinctKeyCap, accumulator, matchingSearchAttributesByWorkflowId);
|
|
141
|
+
matchingStates = [];
|
|
142
|
+
matchingSearchAttributesByWorkflowId = new Map;
|
|
143
|
+
}
|
|
110
144
|
}
|
|
145
|
+
if (matchingStates.length > 0)
|
|
146
|
+
await accumulateAggregateStates(internals, matchingStates, groupBy, distinctKeyCap, accumulator, matchingSearchAttributesByWorkflowId);
|
|
111
147
|
}
|
|
112
148
|
function finalizeAggregateResult(accumulator, requestedLimit) {
|
|
113
149
|
const sortedGroups = [...accumulator.counts.entries()].map(([groupKey, count]) => ({ key: groupKey, count })).toSorted((left, right) => {
|