@temelj/workflow 0.0.0-alpha.1
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/LICENSE +21 -0
- package/README.md +38 -0
- package/dist/attributes.d.mts +15 -0
- package/dist/attributes.mjs +30 -0
- package/dist/client/create.d.mts +31 -0
- package/dist/client/create.mjs +67 -0
- package/dist/client/facades.d.mts +21 -0
- package/dist/client/facades.mjs +142 -0
- package/dist/client/mod.d.mts +2 -0
- package/dist/client/mod.mjs +2 -0
- package/dist/client/run-handle.d.mts +66 -0
- package/dist/client/run-handle.mjs +156 -0
- package/dist/client/worker-options.d.mts +17 -0
- package/dist/client/worker-options.mjs +25 -0
- package/dist/collection.d.mts +15 -0
- package/dist/collection.mjs +33 -0
- package/dist/compiled-function.d.mts +27 -0
- package/dist/compiled-function.mjs +54 -0
- package/dist/definition.d.mts +37 -0
- package/dist/definition.mjs +83 -0
- package/dist/engine/child-workflow.d.mts +10 -0
- package/dist/engine/child-workflow.mjs +333 -0
- package/dist/engine/command-identity.d.mts +9 -0
- package/dist/engine/command-identity.mjs +14 -0
- package/dist/engine/create.d.mts +106 -0
- package/dist/engine/create.mjs +402 -0
- package/dist/engine/deterministic.d.mts +12 -0
- package/dist/engine/deterministic.mjs +102 -0
- package/dist/engine/durable-command.d.mts +10 -0
- package/dist/engine/durable-command.mjs +17 -0
- package/dist/engine/execution-api.d.mts +29 -0
- package/dist/engine/execution-api.mjs +33 -0
- package/dist/engine/execution-service.d.mts +41 -0
- package/dist/engine/execution-service.mjs +288 -0
- package/dist/engine/hooks.d.mts +56 -0
- package/dist/engine/hooks.mjs +237 -0
- package/dist/engine/inspection-api.d.mts +34 -0
- package/dist/engine/inspection-api.mjs +77 -0
- package/dist/engine/inspection.d.mts +18 -0
- package/dist/engine/inspection.mjs +149 -0
- package/dist/engine/lifecycle.d.mts +18 -0
- package/dist/engine/lifecycle.mjs +38 -0
- package/dist/engine/lock-replay.d.mts +30 -0
- package/dist/engine/lock-replay.mjs +38 -0
- package/dist/engine/lock.d.mts +21 -0
- package/dist/engine/lock.mjs +197 -0
- package/dist/engine/message.d.mts +47 -0
- package/dist/engine/message.mjs +357 -0
- package/dist/engine/mod.d.mts +4 -0
- package/dist/engine/mod.mjs +2 -0
- package/dist/engine/observation.d.mts +35 -0
- package/dist/engine/observation.mjs +201 -0
- package/dist/engine/recovery.d.mts +26 -0
- package/dist/engine/recovery.mjs +92 -0
- package/dist/engine/replay.d.mts +41 -0
- package/dist/engine/replay.mjs +122 -0
- package/dist/engine/retry-policy.d.mts +4 -0
- package/dist/engine/retry-policy.mjs +4 -0
- package/dist/engine/retry.d.mts +23 -0
- package/dist/engine/retry.mjs +75 -0
- package/dist/engine/run-data.d.mts +9 -0
- package/dist/engine/run-data.mjs +74 -0
- package/dist/engine/run-service.d.mts +38 -0
- package/dist/engine/run-service.mjs +133 -0
- package/dist/engine/run-utils.d.mts +16 -0
- package/dist/engine/run-utils.mjs +83 -0
- package/dist/engine/schedule.d.mts +25 -0
- package/dist/engine/schedule.mjs +207 -0
- package/dist/engine/serialization.d.mts +9 -0
- package/dist/engine/serialization.mjs +85 -0
- package/dist/engine/start-api.d.mts +30 -0
- package/dist/engine/start-api.mjs +98 -0
- package/dist/engine/state.d.mts +77 -0
- package/dist/engine/state.mjs +464 -0
- package/dist/engine/step-api.d.mts +9 -0
- package/dist/engine/step-api.mjs +25 -0
- package/dist/engine/stream.d.mts +55 -0
- package/dist/engine/stream.mjs +333 -0
- package/dist/engine/summary/active-events.d.mts +34 -0
- package/dist/engine/summary/active-events.mjs +69 -0
- package/dist/engine/summary/child-workflow-runs.d.mts +24 -0
- package/dist/engine/summary/child-workflow-runs.mjs +138 -0
- package/dist/engine/summary/child-workflow-waits.d.mts +21 -0
- package/dist/engine/summary/child-workflow-waits.mjs +67 -0
- package/dist/engine/summary/recovery-child-workflow-waits.d.mts +11 -0
- package/dist/engine/summary/recovery-child-workflow-waits.mjs +89 -0
- package/dist/engine/summary/recovery-due-runs.d.mts +16 -0
- package/dist/engine/summary/recovery-due-runs.mjs +52 -0
- package/dist/engine/summary/recovery-failed-runs.d.mts +14 -0
- package/dist/engine/summary/recovery-failed-runs.mjs +33 -0
- package/dist/engine/summary/recovery-lease-runs.d.mts +16 -0
- package/dist/engine/summary/recovery-lease-runs.mjs +69 -0
- package/dist/engine/summary/recovery-locks.d.mts +18 -0
- package/dist/engine/summary/recovery-locks.mjs +100 -0
- package/dist/engine/summary/recovery-message-waits.d.mts +11 -0
- package/dist/engine/summary/recovery-message-waits.mjs +74 -0
- package/dist/engine/summary/recovery-retry-runs.d.mts +17 -0
- package/dist/engine/summary/recovery-retry-runs.mjs +65 -0
- package/dist/engine/summary/recovery-run-timestamps.d.mts +13 -0
- package/dist/engine/summary/recovery-run-timestamps.mjs +18 -0
- package/dist/engine/summary/recovery-runs.d.mts +23 -0
- package/dist/engine/summary/recovery-runs.mjs +54 -0
- package/dist/engine/summary/recovery-schedules.d.mts +10 -0
- package/dist/engine/summary/recovery-schedules.mjs +46 -0
- package/dist/engine/summary/recovery-sleep-waits.d.mts +10 -0
- package/dist/engine/summary/recovery-sleep-waits.mjs +53 -0
- package/dist/engine/summary/recovery-waits.d.mts +21 -0
- package/dist/engine/summary/recovery-waits.mjs +29 -0
- package/dist/engine/summary/run-availability.d.mts +13 -0
- package/dist/engine/summary/run-availability.mjs +37 -0
- package/dist/engine/summary/run-cleanup.d.mts +14 -0
- package/dist/engine/summary/run-cleanup.mjs +44 -0
- package/dist/engine/summary/run-failure.d.mts +14 -0
- package/dist/engine/summary/run-failure.mjs +62 -0
- package/dist/engine/summary/run-hooks.d.mts +14 -0
- package/dist/engine/summary/run-hooks.mjs +63 -0
- package/dist/engine/summary/run-lease.d.mts +11 -0
- package/dist/engine/summary/run-lease.mjs +64 -0
- package/dist/engine/summary/run-message-waits.d.mts +15 -0
- package/dist/engine/summary/run-message-waits.mjs +62 -0
- package/dist/engine/summary/run-metrics.d.mts +31 -0
- package/dist/engine/summary/run-metrics.mjs +93 -0
- package/dist/engine/summary/run-retry.d.mts +9 -0
- package/dist/engine/summary/run-retry.mjs +69 -0
- package/dist/engine/summary/run-sleeps.d.mts +15 -0
- package/dist/engine/summary/run-sleeps.mjs +61 -0
- package/dist/engine/summary/run-state.d.mts +26 -0
- package/dist/engine/summary/run-state.mjs +48 -0
- package/dist/engine/summary/run-status.d.mts +16 -0
- package/dist/engine/summary/run-status.mjs +35 -0
- package/dist/engine/summary/run-streams.d.mts +14 -0
- package/dist/engine/summary/run-streams.mjs +46 -0
- package/dist/engine/summary/run-transition.d.mts +9 -0
- package/dist/engine/summary/run-transition.mjs +39 -0
- package/dist/engine/summary/run-workflow.d.mts +9 -0
- package/dist/engine/summary/run-workflow.mjs +47 -0
- package/dist/engine/summary/step-attempt-active-child-workflows.d.mts +13 -0
- package/dist/engine/summary/step-attempt-active-child-workflows.mjs +55 -0
- package/dist/engine/summary/step-attempt-active-fields.d.mts +23 -0
- package/dist/engine/summary/step-attempt-active-fields.mjs +14 -0
- package/dist/engine/summary/step-attempt-active-message-waits.d.mts +12 -0
- package/dist/engine/summary/step-attempt-active-message-waits.mjs +47 -0
- package/dist/engine/summary/step-attempt-active-sleeps.d.mts +19 -0
- package/dist/engine/summary/step-attempt-active-sleeps.mjs +44 -0
- package/dist/engine/summary/step-attempt-buckets.d.mts +22 -0
- package/dist/engine/summary/step-attempt-buckets.mjs +152 -0
- package/dist/engine/summary/step-attempt-failure.d.mts +12 -0
- package/dist/engine/summary/step-attempt-failure.mjs +61 -0
- package/dist/engine/summary/step-attempt-lifecycle.d.mts +13 -0
- package/dist/engine/summary/step-attempt-lifecycle.mjs +19 -0
- package/dist/engine/summary/step-attempts.d.mts +11 -0
- package/dist/engine/summary/step-attempts.mjs +43 -0
- package/dist/engine/summary.d.mts +32 -0
- package/dist/engine/summary.mjs +37 -0
- package/dist/engine/task.d.mts +6 -0
- package/dist/engine/task.mjs +207 -0
- package/dist/errors/base.d.mts +99 -0
- package/dist/errors/base.mjs +426 -0
- package/dist/errors/capability.d.mts +11 -0
- package/dist/errors/capability.mjs +23 -0
- package/dist/errors/definition.d.mts +21 -0
- package/dist/errors/definition.mjs +51 -0
- package/dist/errors/details.d.mts +13 -0
- package/dist/errors/details.mjs +65 -0
- package/dist/errors/failures.d.mts +81 -0
- package/dist/errors/failures.mjs +168 -0
- package/dist/errors/hook.d.mts +14 -0
- package/dist/errors/hook.mjs +30 -0
- package/dist/errors/implementation.d.mts +11 -0
- package/dist/errors/implementation.mjs +25 -0
- package/dist/errors/lock.d.mts +28 -0
- package/dist/errors/lock.mjs +70 -0
- package/dist/errors/message.d.mts +106 -0
- package/dist/errors/message.mjs +122 -0
- package/dist/errors/mod.d.mts +17 -0
- package/dist/errors/mod.mjs +17 -0
- package/dist/errors/record-view.d.mts +11 -0
- package/dist/errors/record-view.mjs +24 -0
- package/dist/errors/records.d.mts +7 -0
- package/dist/errors/records.mjs +280 -0
- package/dist/errors/run.d.mts +116 -0
- package/dist/errors/run.mjs +232 -0
- package/dist/errors/runtime.d.mts +12 -0
- package/dist/errors/runtime.mjs +24 -0
- package/dist/errors/schedule.d.mts +27 -0
- package/dist/errors/schedule.mjs +65 -0
- package/dist/errors/step.d.mts +76 -0
- package/dist/errors/step.mjs +113 -0
- package/dist/errors/stream.d.mts +24 -0
- package/dist/errors/stream.mjs +64 -0
- package/dist/esbuild.d.mts +7 -0
- package/dist/esbuild.mjs +6 -0
- package/dist/events/descriptors.d.mts +245 -0
- package/dist/events/descriptors.mjs +405 -0
- package/dist/events/mod.d.mts +3 -0
- package/dist/events/mod.mjs +2 -0
- package/dist/history/attempt-key.d.mts +6 -0
- package/dist/history/attempt-key.mjs +7 -0
- package/dist/history/mod.d.mts +71 -0
- package/dist/history/mod.mjs +195 -0
- package/dist/history/projection.d.mts +8 -0
- package/dist/history/projection.mjs +259 -0
- package/dist/history/replay-projection.d.mts +88 -0
- package/dist/history/replay-projection.mjs +369 -0
- package/dist/history/sequencer.d.mts +16 -0
- package/dist/history/sequencer.mjs +78 -0
- package/dist/history/step-attempts.d.mts +9 -0
- package/dist/history/step-attempts.mjs +50 -0
- package/dist/history/timeline.d.mts +16 -0
- package/dist/history/timeline.mjs +272 -0
- package/dist/history/validator.d.mts +9 -0
- package/dist/history/validator.mjs +110 -0
- package/dist/inspection/mod.d.mts +5 -0
- package/dist/inspection/mod.mjs +3 -0
- package/dist/message-options.d.mts +8 -0
- package/dist/message-options.mjs +25 -0
- package/dist/mod.d.mts +52 -0
- package/dist/mod.mjs +26 -0
- package/dist/otel/support.d.mts +18 -0
- package/dist/otel/support.mjs +102 -0
- package/dist/otel.d.mts +30 -0
- package/dist/otel.mjs +588 -0
- package/dist/pagination.d.mts +25 -0
- package/dist/pagination.mjs +73 -0
- package/dist/registry.d.mts +20 -0
- package/dist/registry.mjs +48 -0
- package/dist/rolldown.d.mts +7 -0
- package/dist/rolldown.mjs +6 -0
- package/dist/rollup.d.mts +7 -0
- package/dist/rollup.mjs +6 -0
- package/dist/rspack.d.mts +7 -0
- package/dist/rspack.mjs +6 -0
- package/dist/runtime.d.mts +34 -0
- package/dist/runtime.mjs +194 -0
- package/dist/step-definition.d.mts +10 -0
- package/dist/step-definition.mjs +15 -0
- package/dist/store/append-projection.d.mts +15 -0
- package/dist/store/append-projection.mjs +26 -0
- package/dist/store/capabilities.d.mts +14 -0
- package/dist/store/capabilities.mjs +42 -0
- package/dist/store/cleanup.d.mts +18 -0
- package/dist/store/cleanup.mjs +338 -0
- package/dist/store/compaction.d.mts +5 -0
- package/dist/store/compaction.mjs +8 -0
- package/dist/store/create.d.mts +52 -0
- package/dist/store/create.mjs +159 -0
- package/dist/store/event-append-project.d.mts +15 -0
- package/dist/store/event-append-project.mjs +77 -0
- package/dist/store/event-append.d.mts +37 -0
- package/dist/store/event-append.mjs +80 -0
- package/dist/store/event-history.d.mts +22 -0
- package/dist/store/event-history.mjs +75 -0
- package/dist/store/event.d.mts +10 -0
- package/dist/store/event.mjs +28 -0
- package/dist/store/idempotency.d.mts +10 -0
- package/dist/store/idempotency.mjs +167 -0
- package/dist/store/instrumentation.d.mts +7 -0
- package/dist/store/instrumentation.mjs +123 -0
- package/dist/store/lock.d.mts +8 -0
- package/dist/store/lock.mjs +28 -0
- package/dist/store/materialization.d.mts +30 -0
- package/dist/store/materialization.mjs +127 -0
- package/dist/store/message-index.d.mts +21 -0
- package/dist/store/message-index.mjs +121 -0
- package/dist/store/mod.d.mts +5 -0
- package/dist/store/mod.mjs +4 -0
- package/dist/store/query.d.mts +24 -0
- package/dist/store/query.mjs +82 -0
- package/dist/store/revision.d.mts +4 -0
- package/dist/store/revision.mjs +7 -0
- package/dist/store/run.d.mts +49 -0
- package/dist/store/run.mjs +236 -0
- package/dist/store/schedule.d.mts +12 -0
- package/dist/store/schedule.mjs +41 -0
- package/dist/store/schema.d.mts +14 -0
- package/dist/store/schema.mjs +17 -0
- package/dist/store/step-attempt.d.mts +14 -0
- package/dist/store/step-attempt.mjs +23 -0
- package/dist/store/storage-value.d.mts +5 -0
- package/dist/store/storage-value.mjs +6 -0
- package/dist/store/validation.d.mts +35 -0
- package/dist/store/validation.mjs +77 -0
- package/dist/store-keys.d.mts +49 -0
- package/dist/store-keys.mjs +63 -0
- package/dist/telemetry.d.mts +132 -0
- package/dist/telemetry.mjs +172 -0
- package/dist/temporal.d.mts +23 -0
- package/dist/temporal.mjs +59 -0
- package/dist/timer.d.mts +12 -0
- package/dist/timer.mjs +28 -0
- package/dist/types/cleanup.d.mts +112 -0
- package/dist/types/cleanup.mjs +22 -0
- package/dist/types/client.d.mts +270 -0
- package/dist/types/client.mjs +1 -0
- package/dist/types/common.d.mts +19 -0
- package/dist/types/common.mjs +15 -0
- package/dist/types/definition.d.mts +92 -0
- package/dist/types/definition.mjs +1 -0
- package/dist/types/engine-options.d.mts +76 -0
- package/dist/types/engine-options.mjs +1 -0
- package/dist/types/engine.d.mts +309 -0
- package/dist/types/engine.mjs +1 -0
- package/dist/types/error-code.d.mts +256 -0
- package/dist/types/error-code.mjs +131 -0
- package/dist/types/error.d.mts +236 -0
- package/dist/types/error.mjs +48 -0
- package/dist/types/events.d.mts +2869 -0
- package/dist/types/events.mjs +283 -0
- package/dist/types/hook.d.mts +149 -0
- package/dist/types/hook.mjs +66 -0
- package/dist/types/lock.d.mts +63 -0
- package/dist/types/lock.mjs +18 -0
- package/dist/types/message-id.d.mts +7 -0
- package/dist/types/message-id.mjs +5 -0
- package/dist/types/message.d.mts +87 -0
- package/dist/types/message.mjs +1 -0
- package/dist/types/observation.d.mts +146 -0
- package/dist/types/observation.mjs +1 -0
- package/dist/types/pagination.d.mts +32 -0
- package/dist/types/pagination.mjs +13 -0
- package/dist/types/result.d.mts +62 -0
- package/dist/types/result.mjs +1 -0
- package/dist/types/retry.d.mts +48 -0
- package/dist/types/retry.mjs +1 -0
- package/dist/types/run-id.d.mts +7 -0
- package/dist/types/run-id.mjs +5 -0
- package/dist/types/run-list.d.mts +43 -0
- package/dist/types/run-list.mjs +1 -0
- package/dist/types/run-options.d.mts +86 -0
- package/dist/types/run-options.mjs +1 -0
- package/dist/types/run.d.mts +355 -0
- package/dist/types/run.mjs +207 -0
- package/dist/types/runtime.d.mts +143 -0
- package/dist/types/runtime.mjs +21 -0
- package/dist/types/schedule.d.mts +127 -0
- package/dist/types/schedule.mjs +48 -0
- package/dist/types/step-attempts.d.mts +326 -0
- package/dist/types/step-attempts.mjs +43 -0
- package/dist/types/step-id.d.mts +7 -0
- package/dist/types/step-id.mjs +5 -0
- package/dist/types/step.d.mts +183 -0
- package/dist/types/step.mjs +5 -0
- package/dist/types/store.d.mts +254 -0
- package/dist/types/store.mjs +1 -0
- package/dist/types/stream-id.d.mts +7 -0
- package/dist/types/stream-id.mjs +5 -0
- package/dist/types/stream.d.mts +126 -0
- package/dist/types/stream.mjs +1 -0
- package/dist/types/summary.d.mts +318 -0
- package/dist/types/summary.mjs +1 -0
- package/dist/types/telemetry.d.mts +74 -0
- package/dist/types/telemetry.mjs +9 -0
- package/dist/types/timeline.d.mts +237 -0
- package/dist/types/timeline.mjs +1 -0
- package/dist/types/vite.d.mts +65 -0
- package/dist/types/vite.mjs +1 -0
- package/dist/types/worker-id.d.mts +7 -0
- package/dist/types/worker-id.mjs +5 -0
- package/dist/types/worker.d.mts +94 -0
- package/dist/types/worker.mjs +1 -0
- package/dist/utility.d.mts +49 -0
- package/dist/utility.mjs +122 -0
- package/dist/vite/ast.d.mts +23 -0
- package/dist/vite/ast.mjs +73 -0
- package/dist/vite/error.d.mts +19 -0
- package/dist/vite/error.mjs +47 -0
- package/dist/vite/generated-name.d.mts +7 -0
- package/dist/vite/generated-name.mjs +9 -0
- package/dist/vite/manifest.d.mts +7 -0
- package/dist/vite/manifest.mjs +106 -0
- package/dist/vite/plugin.d.mts +7 -0
- package/dist/vite/plugin.mjs +190 -0
- package/dist/vite/safety.d.mts +12 -0
- package/dist/vite/safety.mjs +96 -0
- package/dist/vite/source-edit.d.mts +12 -0
- package/dist/vite/source-edit.mjs +44 -0
- package/dist/vite/source-map.d.mts +11 -0
- package/dist/vite/source-map.mjs +53 -0
- package/dist/vite/source.d.mts +7 -0
- package/dist/vite/source.mjs +14 -0
- package/dist/vite/transform.d.mts +7 -0
- package/dist/vite/transform.mjs +405 -0
- package/dist/vite.d.mts +6 -0
- package/dist/vite.mjs +5 -0
- package/dist/webhook.d.mts +16 -0
- package/dist/webhook.mjs +17 -0
- package/dist/webpack.d.mts +7 -0
- package/dist/webpack.mjs +6 -0
- package/dist/worker/error.d.mts +11 -0
- package/dist/worker/error.mjs +40 -0
- package/dist/worker.d.mts +18 -0
- package/dist/worker.mjs +427 -0
- package/package.json +144 -0
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
import { WorkflowStateError } from "../errors/base.mjs";
|
|
2
|
+
import { makeWorkflowStepAttemptKey } from "../history/attempt-key.mjs";
|
|
3
|
+
import { isTerminalWorkflowRunStatus } from "../utility.mjs";
|
|
4
|
+
import { omitUndefined } from "../collection.mjs";
|
|
5
|
+
import "../errors/mod.mjs";
|
|
6
|
+
import { compareOptionalTimestamps } from "../temporal.mjs";
|
|
7
|
+
import "../history/mod.mjs";
|
|
8
|
+
import { supportsWorkflowConditionalWrite } from "./capabilities.mjs";
|
|
9
|
+
import { makeCleanupMarkerKey, makeCleanupMarkerKeyPrefix, makeEventsKey, makeIdempotencyKey, makeMessageIdempotencyKey, makeRunKey, makeStepAttemptKeyPrefix } from "../store-keys.mjs";
|
|
10
|
+
import { isSameWorkflowStorageValue } from "./revision.mjs";
|
|
11
|
+
import { toStorageValue } from "./storage-value.mjs";
|
|
12
|
+
import { isReadableMessageIdempotencyIndex, isSameMessageIdempotencyIndex, readableCleanupMarkerRecord } from "./validation.mjs";
|
|
13
|
+
import { getStoredCleanupEventHistory } from "./event-history.mjs";
|
|
14
|
+
import { getReadableStoredWorkflowRun } from "./run.mjs";
|
|
15
|
+
import { messageIdempotencyIndexValuesFromEvents } from "./message-index.mjs";
|
|
16
|
+
//#region src/store/cleanup.ts
|
|
17
|
+
async function stepAttemptKeysForCleanup(storage, namespace, runId) {
|
|
18
|
+
const prefix = makeStepAttemptKeyPrefix(namespace, runId);
|
|
19
|
+
return [...new Set((await storage.keys({ prefix })).filter((key) => isStepAttemptKey(key, prefix)))];
|
|
20
|
+
}
|
|
21
|
+
function isStepAttemptKey(key, prefix) {
|
|
22
|
+
if (!key.startsWith(prefix)) return false;
|
|
23
|
+
const attemptKey = decodeStepAttemptKey(key, prefix);
|
|
24
|
+
if (attemptKey === void 0) return false;
|
|
25
|
+
const separator = attemptKey.lastIndexOf(":");
|
|
26
|
+
if (!attemptKey.startsWith("run:") || separator <= 4) return false;
|
|
27
|
+
const stepId = attemptKey.slice(4, separator);
|
|
28
|
+
const attempt = Number(attemptKey.slice(separator + 1));
|
|
29
|
+
try {
|
|
30
|
+
return makeWorkflowStepAttemptKey(stepId, attempt) === attemptKey;
|
|
31
|
+
} catch {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function decodeStepAttemptKey(key, prefix) {
|
|
36
|
+
try {
|
|
37
|
+
return decodeURIComponent(key.slice(prefix.length));
|
|
38
|
+
} catch {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
async function messageIdempotencyIndexesForCleanup(storage, namespace, runId, events) {
|
|
43
|
+
const candidatesByKey = /* @__PURE__ */ new Map();
|
|
44
|
+
for (const candidate of messageIdempotencyIndexesFromEvents(namespace, runId, events)) candidatesByKey.set(candidate.key, [...candidatesByKey.get(candidate.key) ?? [], candidate]);
|
|
45
|
+
return (await Promise.all([...candidatesByKey.keys()].map(async (key) => ({
|
|
46
|
+
key,
|
|
47
|
+
value: await storage.get(key)
|
|
48
|
+
})))).filter((entry) => isCurrentMessageIdempotencyIndex(candidatesByKey.get(entry.key) ?? [], entry.value)).map(toCleanupIndex);
|
|
49
|
+
}
|
|
50
|
+
async function idempotencyIndexesForCleanup(storage, namespace, run) {
|
|
51
|
+
if (run.idempotencyKey === void 0) return [];
|
|
52
|
+
const key = idempotencyKeyFromRun(namespace, run);
|
|
53
|
+
const value = await storage.get(key);
|
|
54
|
+
return value === run.id ? [{
|
|
55
|
+
key,
|
|
56
|
+
value
|
|
57
|
+
}] : [];
|
|
58
|
+
}
|
|
59
|
+
async function deleteCleanupIndexes(storage, indexes) {
|
|
60
|
+
const uniqueIndexes = indexes.filter(uniqueCleanupIndexKey);
|
|
61
|
+
if (!supportsWorkflowConditionalWrite(storage)) {
|
|
62
|
+
const currentIndexes = await Promise.all(uniqueIndexes.map(async (index) => ({
|
|
63
|
+
...index,
|
|
64
|
+
current: await storage.get(index.key)
|
|
65
|
+
})));
|
|
66
|
+
return await storage.deleteMany(currentIndexes.flatMap((index) => workflowCleanupIndexMatchesCurrentValue(index.current, index.value) ? [index.key] : []));
|
|
67
|
+
}
|
|
68
|
+
return (await Promise.all(uniqueIndexes.map(async (index) => await storage.compareAndSet(index.key, index.value, void 0)))).filter((value) => value).length;
|
|
69
|
+
}
|
|
70
|
+
function workflowCleanupIndexMatchesCurrentValue(current, expected) {
|
|
71
|
+
if (isReadableMessageIdempotencyIndex(expected)) return isSameMessageIdempotencyIndex(current, expected);
|
|
72
|
+
return isSameWorkflowStorageValue(current, expected);
|
|
73
|
+
}
|
|
74
|
+
function messageIdempotencyIndexesFromEvents(namespace, runId, events) {
|
|
75
|
+
return messageIdempotencyIndexValuesFromEvents(events, runId).map(({ idempotencyKey, value }) => ({
|
|
76
|
+
key: makeMessageIdempotencyKey(namespace, runId, idempotencyKey),
|
|
77
|
+
value
|
|
78
|
+
}));
|
|
79
|
+
}
|
|
80
|
+
function idempotencyKeyFromRun(namespace, run) {
|
|
81
|
+
if (run.idempotencyKey === void 0) WorkflowStateError.runMissingIdempotencyKey(run.id);
|
|
82
|
+
return makeIdempotencyKey(namespace, {
|
|
83
|
+
workflowName: run.workflowName,
|
|
84
|
+
...run.workflowVersion === void 0 ? {} : { workflowVersion: run.workflowVersion },
|
|
85
|
+
idempotencyKey: run.idempotencyKey
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
function toCleanupIndex(entry) {
|
|
89
|
+
return {
|
|
90
|
+
key: entry.key,
|
|
91
|
+
value: toStorageValue(entry.value)
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function isCurrentMessageIdempotencyIndex(eventIndexes, value) {
|
|
95
|
+
if (!isReadableMessageIdempotencyIndex(value)) return false;
|
|
96
|
+
return eventIndexes.some((eventIndex) => isSameMessageIdempotencyIndex(value, eventIndex.value));
|
|
97
|
+
}
|
|
98
|
+
function uniqueCleanupIndexKey(index, position, indexes) {
|
|
99
|
+
return indexes.findIndex((current) => current.key === index.key) === position;
|
|
100
|
+
}
|
|
101
|
+
async function cleanupRuns(storage, namespace, runs, options) {
|
|
102
|
+
const cleanupOptions = options;
|
|
103
|
+
const limit = cleanupOptions.limit;
|
|
104
|
+
const statusFilter = cleanupOptions.status ?? [
|
|
105
|
+
"completed",
|
|
106
|
+
"failed",
|
|
107
|
+
"canceled"
|
|
108
|
+
];
|
|
109
|
+
const selectedRuns = (await runs.listRuns({
|
|
110
|
+
status: Array.isArray(statusFilter) ? [...statusFilter] : statusFilter,
|
|
111
|
+
workflowName: cleanupOptions.workflowName,
|
|
112
|
+
workflowVersion: cleanupOptions.workflowVersion,
|
|
113
|
+
idempotencyKey: cleanupOptions.idempotencyKey,
|
|
114
|
+
parentRunId: cleanupOptions.parentRunId,
|
|
115
|
+
parentStepId: cleanupOptions.parentStepId,
|
|
116
|
+
parentStepName: cleanupOptions.parentStepName,
|
|
117
|
+
parentStepAttempt: cleanupOptions.parentStepAttempt
|
|
118
|
+
})).filter((run) => isWorkflowRunEligibleForCleanup(run, cleanupOptions)).sort(compareCleanupRuns).filter(isFirstCleanupRunForId).slice(0, limit);
|
|
119
|
+
const stepAttemptKeysByRun = await Promise.all(selectedRuns.map(async (run) => await stepAttemptKeysForCleanup(storage, namespace, run.id)));
|
|
120
|
+
const stepAttemptKeys = stepAttemptKeysByRun.flat();
|
|
121
|
+
const eventKeysByRun = selectedRuns.map((run) => makeEventsKey(namespace, run.id));
|
|
122
|
+
const storedEventsByRun = await Promise.all(eventKeysByRun.map(async (key) => {
|
|
123
|
+
const eventHistory = await getStoredCleanupEventHistory(storage, key);
|
|
124
|
+
return {
|
|
125
|
+
exists: eventHistory.raw !== void 0,
|
|
126
|
+
events: eventHistory.events
|
|
127
|
+
};
|
|
128
|
+
}));
|
|
129
|
+
const runEvents = storedEventsByRun.map((entry) => entry.events);
|
|
130
|
+
const eventKeysForCleanup = eventKeysByRun.map((key, index) => storedEventsByRun[index]?.exists === true ? key : void 0);
|
|
131
|
+
const eventKeys = eventKeysForCleanup.filter((key) => key !== void 0);
|
|
132
|
+
const runKeys = selectedRuns.map((run) => ({
|
|
133
|
+
key: makeRunKey(namespace, run.id),
|
|
134
|
+
run
|
|
135
|
+
}));
|
|
136
|
+
const idempotencyIndexesByRun = await Promise.all(selectedRuns.map(async (run) => await idempotencyIndexesForCleanup(storage, namespace, run)));
|
|
137
|
+
const idempotencyKeysByRun = idempotencyIndexesByRun.map((indexes) => indexes.map((index) => index.key));
|
|
138
|
+
const idempotencyKeys = idempotencyKeysByRun.flat();
|
|
139
|
+
const messageIdempotencyIndexesByRun = await Promise.all(selectedRuns.map(async (run, index) => await messageIdempotencyIndexesForCleanup(storage, namespace, run.id, runEvents[index] ?? [])));
|
|
140
|
+
const messageIdempotencyKeysByRun = messageIdempotencyIndexesByRun.map((indexes) => indexes.map((index) => index.key));
|
|
141
|
+
const messageIdempotencyKeys = messageIdempotencyKeysByRun.flat();
|
|
142
|
+
const deletionResults = cleanupOptions.dryRun === true ? selectedRuns.map(() => ({
|
|
143
|
+
cleanupMarkerCreated: false,
|
|
144
|
+
cleanupMarkerDeleted: false,
|
|
145
|
+
runDeleted: false,
|
|
146
|
+
deletedEvents: 0,
|
|
147
|
+
deletedStepAttempts: 0,
|
|
148
|
+
deletedIdempotencyKeys: 0,
|
|
149
|
+
deletedMessageIdempotencyKeys: 0
|
|
150
|
+
})) : await deleteCleanupRunsAndArtifacts(storage, {
|
|
151
|
+
namespace,
|
|
152
|
+
runs: runKeys,
|
|
153
|
+
eventKeysByRun: eventKeysForCleanup,
|
|
154
|
+
stepAttemptKeysByRun,
|
|
155
|
+
idempotencyIndexesByRun,
|
|
156
|
+
messageIdempotencyIndexesByRun
|
|
157
|
+
});
|
|
158
|
+
const deletedRuns = countCleanupDeletionResult(deletionResults, "runDeleted");
|
|
159
|
+
const createdCleanupMarkers = countCleanupDeletionResult(deletionResults, "cleanupMarkerCreated");
|
|
160
|
+
const deletedCleanupMarkers = countCleanupDeletionResult(deletionResults, "cleanupMarkerDeleted");
|
|
161
|
+
const deletedEvents = sumCleanupDeletionResult(deletionResults, "deletedEvents");
|
|
162
|
+
const deletedStepAttempts = sumCleanupDeletionResult(deletionResults, "deletedStepAttempts");
|
|
163
|
+
const deletedIdempotencyKeys = sumCleanupDeletionResult(deletionResults, "deletedIdempotencyKeys");
|
|
164
|
+
const deletedMessageIdempotencyKeys = sumCleanupDeletionResult(deletionResults, "deletedMessageIdempotencyKeys");
|
|
165
|
+
return {
|
|
166
|
+
mode: "best_effort",
|
|
167
|
+
runIds: selectedRuns.map((run) => run.id),
|
|
168
|
+
runs: selectedRuns.map((run, index) => ({
|
|
169
|
+
mode: "best_effort",
|
|
170
|
+
runId: run.id,
|
|
171
|
+
workflowName: run.workflowName,
|
|
172
|
+
...run.workflowVersion === void 0 ? {} : { workflowVersion: run.workflowVersion },
|
|
173
|
+
status: isTerminalWorkflowRunStatus(run.status) ? run.status : (() => {
|
|
174
|
+
WorkflowStateError.cleanupSelectedNonTerminalRun(run.id);
|
|
175
|
+
})(),
|
|
176
|
+
createdAt: run.createdAt,
|
|
177
|
+
updatedAt: run.updatedAt,
|
|
178
|
+
finishedAt: cleanupFinishedAt(run),
|
|
179
|
+
...run.idempotencyKey === void 0 ? {} : { idempotencyKey: run.idempotencyKey },
|
|
180
|
+
...run.parentRunId === void 0 ? {} : { parentRunId: run.parentRunId },
|
|
181
|
+
...run.parentStepId === void 0 ? {} : { parentStepId: run.parentStepId },
|
|
182
|
+
...run.parentStepName === void 0 ? {} : { parentStepName: run.parentStepName },
|
|
183
|
+
...run.parentStepAttempt === void 0 ? {} : { parentStepAttempt: run.parentStepAttempt },
|
|
184
|
+
events: runEvents[index]?.length ?? 0,
|
|
185
|
+
stepAttempts: stepAttemptKeysByRun[index]?.length ?? 0,
|
|
186
|
+
idempotencyKeys: idempotencyKeysByRun[index]?.length ?? 0,
|
|
187
|
+
messageIdempotencyKeys: messageIdempotencyKeysByRun[index]?.length ?? 0,
|
|
188
|
+
cleanupMarkerCreated: deletionResults[index]?.cleanupMarkerCreated ?? false,
|
|
189
|
+
cleanupMarkerDeleted: deletionResults[index]?.cleanupMarkerDeleted ?? false,
|
|
190
|
+
runDeleted: deletionResults[index]?.runDeleted ?? false,
|
|
191
|
+
deletedEvents: deletionResults[index]?.deletedEvents ?? 0,
|
|
192
|
+
deletedStepAttempts: deletionResults[index]?.deletedStepAttempts ?? 0,
|
|
193
|
+
deletedIdempotencyKeys: deletionResults[index]?.deletedIdempotencyKeys ?? 0,
|
|
194
|
+
deletedMessageIdempotencyKeys: deletionResults[index]?.deletedMessageIdempotencyKeys ?? 0
|
|
195
|
+
})),
|
|
196
|
+
...cleanupOptions.dryRun === true ? {
|
|
197
|
+
dryRun: true,
|
|
198
|
+
matchedRuns: selectedRuns.length,
|
|
199
|
+
matchedEvents: eventKeys.length,
|
|
200
|
+
matchedStepAttempts: stepAttemptKeys.length,
|
|
201
|
+
matchedIdempotencyKeys: idempotencyKeys.length,
|
|
202
|
+
matchedMessageIdempotencyKeys: messageIdempotencyKeys.length
|
|
203
|
+
} : {},
|
|
204
|
+
deletedRuns,
|
|
205
|
+
createdCleanupMarkers,
|
|
206
|
+
deletedCleanupMarkers,
|
|
207
|
+
deletedEvents,
|
|
208
|
+
deletedStepAttempts,
|
|
209
|
+
deletedIdempotencyKeys,
|
|
210
|
+
deletedMessageIdempotencyKeys
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
async function listCleanupMarkers(storage, namespace) {
|
|
214
|
+
const prefix = makeCleanupMarkerKeyPrefix(namespace);
|
|
215
|
+
return (await Promise.all((await storage.keys({ prefix })).filter((key) => isCleanupMarkerKey(key, prefix)).map(async (key) => await storage.get(key)))).flatMap((marker) => {
|
|
216
|
+
const parsed = readableCleanupMarkerRecord(marker);
|
|
217
|
+
return parsed === void 0 ? [] : [parsed];
|
|
218
|
+
}).sort(compareCleanupMarkers);
|
|
219
|
+
}
|
|
220
|
+
function isCleanupMarkerKey(key, prefix) {
|
|
221
|
+
return key.startsWith(prefix);
|
|
222
|
+
}
|
|
223
|
+
function compareCleanupMarkers(left, right) {
|
|
224
|
+
return Temporal.Instant.compare(left.cleanupStartedAt, right.cleanupStartedAt) || left.runId.localeCompare(right.runId);
|
|
225
|
+
}
|
|
226
|
+
function sumCleanupDeletionResult(results, key) {
|
|
227
|
+
return results.reduce((total, result) => total + result[key], 0);
|
|
228
|
+
}
|
|
229
|
+
function countCleanupDeletionResult(results, key) {
|
|
230
|
+
return results.filter((result) => result[key]).length;
|
|
231
|
+
}
|
|
232
|
+
function cleanupFinishedAt(run) {
|
|
233
|
+
if (run.finishedAt === void 0) WorkflowStateError.cleanupRunMissingFinishedAt(run.id);
|
|
234
|
+
return run.finishedAt;
|
|
235
|
+
}
|
|
236
|
+
function isWorkflowRunEligibleForCleanup(run, options) {
|
|
237
|
+
if (!isTerminalWorkflowRunStatus(run.status) || run.finishedAt === void 0) return false;
|
|
238
|
+
if (Temporal.Instant.compare(run.finishedAt, options.finishedAtBefore) >= 0) return false;
|
|
239
|
+
return options.status === void 0 || matchesCleanupStatus(run.status, options.status);
|
|
240
|
+
}
|
|
241
|
+
function matchesCleanupStatus(status, filter) {
|
|
242
|
+
return Array.isArray(filter) ? filter.includes(status) : status === filter;
|
|
243
|
+
}
|
|
244
|
+
function compareCleanupRuns(left, right) {
|
|
245
|
+
const finishedOrder = compareOptionalTimestamps(left.finishedAt, right.finishedAt);
|
|
246
|
+
if (finishedOrder !== 0) return finishedOrder;
|
|
247
|
+
const createdOrder = compareOptionalTimestamps(left.createdAt, right.createdAt);
|
|
248
|
+
if (createdOrder !== 0) return createdOrder;
|
|
249
|
+
return left.id.localeCompare(right.id);
|
|
250
|
+
}
|
|
251
|
+
function isFirstCleanupRunForId(run, index, runs) {
|
|
252
|
+
return runs.findIndex((entry) => entry.id === run.id) === index;
|
|
253
|
+
}
|
|
254
|
+
async function deleteCleanupRunsAndArtifacts(storage, options) {
|
|
255
|
+
const markers = await createCleanupMarkers(storage, options);
|
|
256
|
+
const deletedRuns = await deleteCleanupRunRecords(storage, options.runs);
|
|
257
|
+
return await Promise.all(deletedRuns.map(async (runDeleted, index) => {
|
|
258
|
+
const marker = markers[index];
|
|
259
|
+
if (!runDeleted) return {
|
|
260
|
+
cleanupMarkerCreated: marker?.created ?? false,
|
|
261
|
+
cleanupMarkerDeleted: false,
|
|
262
|
+
runDeleted: false,
|
|
263
|
+
deletedEvents: 0,
|
|
264
|
+
deletedStepAttempts: 0,
|
|
265
|
+
deletedIdempotencyKeys: 0,
|
|
266
|
+
deletedMessageIdempotencyKeys: 0
|
|
267
|
+
};
|
|
268
|
+
const eventKeys = options.eventKeysByRun[index] === void 0 ? [] : [options.eventKeysByRun[index]];
|
|
269
|
+
const [deletedEvents, deletedStepAttempts, deletedIdempotencyKeys, deletedMessageIdempotencyKeys] = await Promise.all([
|
|
270
|
+
storage.deleteMany(eventKeys),
|
|
271
|
+
storage.deleteMany(options.stepAttemptKeysByRun[index] ?? []),
|
|
272
|
+
deleteCleanupIndexes(storage, options.idempotencyIndexesByRun[index] ?? []),
|
|
273
|
+
deleteCleanupIndexes(storage, options.messageIdempotencyIndexesByRun[index] ?? [])
|
|
274
|
+
]);
|
|
275
|
+
const cleanupMarkerDeleted = marker?.key !== void 0 && deletionCompleted({
|
|
276
|
+
deletedEvents,
|
|
277
|
+
expectedEvents: eventKeys.length,
|
|
278
|
+
deletedStepAttempts,
|
|
279
|
+
expectedStepAttempts: options.stepAttemptKeysByRun[index]?.length ?? 0,
|
|
280
|
+
deletedIdempotencyKeys,
|
|
281
|
+
expectedIdempotencyKeys: options.idempotencyIndexesByRun[index]?.length ?? 0,
|
|
282
|
+
deletedMessageIdempotencyKeys,
|
|
283
|
+
expectedMessageIdempotencyKeys: options.messageIdempotencyIndexesByRun[index]?.length ?? 0
|
|
284
|
+
});
|
|
285
|
+
if (cleanupMarkerDeleted) await storage.delete(marker.key);
|
|
286
|
+
return {
|
|
287
|
+
cleanupMarkerCreated: marker?.created ?? false,
|
|
288
|
+
cleanupMarkerDeleted,
|
|
289
|
+
runDeleted: true,
|
|
290
|
+
deletedEvents,
|
|
291
|
+
deletedStepAttempts,
|
|
292
|
+
deletedIdempotencyKeys,
|
|
293
|
+
deletedMessageIdempotencyKeys
|
|
294
|
+
};
|
|
295
|
+
}));
|
|
296
|
+
}
|
|
297
|
+
async function createCleanupMarkers(storage, options) {
|
|
298
|
+
const cleanupStartedAt = Temporal.Now.instant();
|
|
299
|
+
return await Promise.all(options.runs.map(async ({ run }, index) => {
|
|
300
|
+
const key = makeCleanupMarkerKey(options.namespace, run.id);
|
|
301
|
+
const marker = {
|
|
302
|
+
mode: "best_effort",
|
|
303
|
+
runId: run.id,
|
|
304
|
+
workflowName: run.workflowName,
|
|
305
|
+
...run.workflowVersion === void 0 ? {} : { workflowVersion: run.workflowVersion },
|
|
306
|
+
status: isTerminalWorkflowRunStatus(run.status) ? run.status : (() => {
|
|
307
|
+
WorkflowStateError.cleanupSelectedNonTerminalRun(run.id);
|
|
308
|
+
})(),
|
|
309
|
+
createdAt: run.createdAt,
|
|
310
|
+
finishedAt: cleanupFinishedAt(run),
|
|
311
|
+
cleanupStartedAt,
|
|
312
|
+
events: options.eventKeysByRun[index] === void 0 ? 0 : 1,
|
|
313
|
+
stepAttempts: options.stepAttemptKeysByRun[index]?.length ?? 0,
|
|
314
|
+
idempotencyKeys: options.idempotencyIndexesByRun[index]?.length ?? 0,
|
|
315
|
+
messageIdempotencyKeys: options.messageIdempotencyIndexesByRun[index]?.length ?? 0
|
|
316
|
+
};
|
|
317
|
+
await storage.set(key, toStorageValue(marker));
|
|
318
|
+
return {
|
|
319
|
+
key,
|
|
320
|
+
created: true
|
|
321
|
+
};
|
|
322
|
+
}));
|
|
323
|
+
}
|
|
324
|
+
function deletionCompleted(options) {
|
|
325
|
+
return options.deletedEvents === options.expectedEvents && options.deletedStepAttempts === options.expectedStepAttempts && options.deletedIdempotencyKeys === options.expectedIdempotencyKeys && options.deletedMessageIdempotencyKeys === options.expectedMessageIdempotencyKeys;
|
|
326
|
+
}
|
|
327
|
+
async function deleteCleanupRunRecords(storage, runs) {
|
|
328
|
+
if (!supportsWorkflowConditionalWrite(storage)) {
|
|
329
|
+
const deletedRuns = (await Promise.all(runs.map(async (run) => {
|
|
330
|
+
return await getReadableStoredWorkflowRun(storage, run.run.namespace, run.run.id);
|
|
331
|
+
}))).map((latest, index) => latest !== void 0 && isSameWorkflowStorageValue(omitUndefined(latest), omitUndefined(runs[index].run)));
|
|
332
|
+
await storage.deleteMany(runs.flatMap((run, index) => deletedRuns[index] === true ? [run.key] : []));
|
|
333
|
+
return deletedRuns;
|
|
334
|
+
}
|
|
335
|
+
return await Promise.all(runs.map(async (run) => await storage.compareAndSet(run.key, toStorageValue(run.run), void 0)));
|
|
336
|
+
}
|
|
337
|
+
//#endregion
|
|
338
|
+
export { cleanupRuns, deleteCleanupIndexes, idempotencyIndexesForCleanup, listCleanupMarkers, messageIdempotencyIndexesForCleanup, stepAttemptKeysForCleanup };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
//#region src/store/compaction.d.ts
|
|
2
|
+
/** Removes undefined optional fields before persisting a workflow store record. */
|
|
3
|
+
declare function compactWorkflowStoreRecord<TRecord extends object>(record: TRecord): TRecord;
|
|
4
|
+
//#endregion
|
|
5
|
+
export { compactWorkflowStoreRecord };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { omitUndefined } from "../collection.mjs";
|
|
2
|
+
//#region src/store/compaction.ts
|
|
3
|
+
/** Removes undefined optional fields before persisting a workflow store record. */
|
|
4
|
+
function compactWorkflowStoreRecord(record) {
|
|
5
|
+
return omitUndefined(record);
|
|
6
|
+
}
|
|
7
|
+
//#endregion
|
|
8
|
+
export { compactWorkflowStoreRecord };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { RunId } from "../types/run-id.mjs";
|
|
2
|
+
import { CleanupMarkerRecord, CleanupRunsOptions, CleanupRunsResult } from "../types/cleanup.mjs";
|
|
3
|
+
import { WorkflowPage } from "../types/pagination.mjs";
|
|
4
|
+
import { ListSchedulesOptions, ListSchedulesPageOptions, ScheduleRecord } from "../types/schedule.mjs";
|
|
5
|
+
import { LockRecord } from "../types/lock.mjs";
|
|
6
|
+
import { WorkflowListRunsOptions, WorkflowListRunsPageOptions, WorkflowListStepAttemptsPageOptions } from "../types/run-list.mjs";
|
|
7
|
+
import { WorkflowListStepAttemptsOptions, WorkflowStepAttemptRecord } from "../types/step-attempts.mjs";
|
|
8
|
+
import { WorkflowRunRecord } from "../types/run.mjs";
|
|
9
|
+
import { EventRecord } from "../types/events.mjs";
|
|
10
|
+
import { CreateWorkflowStoreOptions, WorkflowClaimRunOptions, WorkflowEventHistoryChangeWaitOptions, WorkflowExtendRunLeaseOptions, WorkflowIdempotencyKeyOptions, WorkflowMessageIdempotencyIndex, WorkflowReleaseRunLeaseOptions, WorkflowStorage, WorkflowStore as WorkflowStore$1, WorkflowStoreCapabilities } from "../types/store.mjs";
|
|
11
|
+
//#region src/store/create.d.ts
|
|
12
|
+
declare function createWorkflowStore(options?: CreateWorkflowStoreOptions): WorkflowStore$1;
|
|
13
|
+
/** Storage-backed workflow store implementation. */
|
|
14
|
+
declare class WorkflowStore implements WorkflowStore$1 {
|
|
15
|
+
readonly storage: WorkflowStorage;
|
|
16
|
+
readonly namespace: string;
|
|
17
|
+
readonly capabilities: WorkflowStoreCapabilities;
|
|
18
|
+
constructor(options?: CreateWorkflowStoreOptions);
|
|
19
|
+
createRun(run: WorkflowRunRecord): Promise<WorkflowRunRecord>;
|
|
20
|
+
getRun(runId: RunId): Promise<WorkflowRunRecord | undefined>;
|
|
21
|
+
getRunByIdempotencyKey(options: WorkflowIdempotencyKeyOptions): Promise<WorkflowRunRecord | undefined>;
|
|
22
|
+
updateRun(run: WorkflowRunRecord): Promise<WorkflowRunRecord>;
|
|
23
|
+
updateRunIfCurrent(current: WorkflowRunRecord, next: WorkflowRunRecord): Promise<WorkflowRunRecord | undefined>;
|
|
24
|
+
listRuns(options?: WorkflowListRunsOptions): Promise<readonly WorkflowRunRecord[]>;
|
|
25
|
+
listRunsPage(options?: WorkflowListRunsPageOptions): Promise<WorkflowPage<WorkflowRunRecord>>;
|
|
26
|
+
countRuns(options?: WorkflowListRunsOptions): Promise<number>;
|
|
27
|
+
claimRun(options: WorkflowClaimRunOptions): Promise<WorkflowRunRecord | undefined>;
|
|
28
|
+
extendRunLease(options: WorkflowExtendRunLeaseOptions): Promise<WorkflowRunRecord | undefined>;
|
|
29
|
+
releaseRunLease(options: WorkflowReleaseRunLeaseOptions): Promise<WorkflowRunRecord | undefined>;
|
|
30
|
+
appendEvent(runId: RunId, event: EventRecord): Promise<readonly EventRecord[]>;
|
|
31
|
+
appendEventIfRunCurrent(current: WorkflowRunRecord, event: EventRecord): Promise<readonly EventRecord[] | undefined>;
|
|
32
|
+
getEvents(runId: RunId): Promise<readonly EventRecord[]>;
|
|
33
|
+
waitForEventHistoryChange(runId: RunId, options?: WorkflowEventHistoryChangeWaitOptions): Promise<void>;
|
|
34
|
+
listStepAttempts(runId: RunId, options?: WorkflowListStepAttemptsOptions): Promise<readonly WorkflowStepAttemptRecord[]>;
|
|
35
|
+
listStepAttemptsPage(runId: RunId, options?: WorkflowListStepAttemptsPageOptions): Promise<WorkflowPage<WorkflowStepAttemptRecord>>;
|
|
36
|
+
countStepAttempts(runId: RunId, options?: WorkflowListStepAttemptsOptions): Promise<number>;
|
|
37
|
+
repairStepAttempts(runId: RunId): Promise<readonly WorkflowStepAttemptRecord[]>;
|
|
38
|
+
repairMessageIdempotencyIndexes(runId: RunId): Promise<readonly WorkflowMessageIdempotencyIndex[]>;
|
|
39
|
+
hasMessageIdempotencyKey(runId: RunId, idempotencyKey: string): Promise<boolean>;
|
|
40
|
+
cleanupRuns(options: CleanupRunsOptions): Promise<CleanupRunsResult>;
|
|
41
|
+
listCleanupMarkers(): Promise<readonly CleanupMarkerRecord[]>;
|
|
42
|
+
createSchedule<TInput>(schedule: ScheduleRecord<TInput>): Promise<ScheduleRecord<TInput>>;
|
|
43
|
+
getSchedule(scheduleId: string): Promise<ScheduleRecord | undefined>;
|
|
44
|
+
updateScheduleIfCurrent<TInput>(current: ScheduleRecord, next: ScheduleRecord<TInput>): Promise<ScheduleRecord<TInput> | undefined>;
|
|
45
|
+
listSchedules(options?: ListSchedulesOptions): Promise<readonly ScheduleRecord[]>;
|
|
46
|
+
listSchedulesPage(options?: ListSchedulesPageOptions): Promise<WorkflowPage<ScheduleRecord>>;
|
|
47
|
+
getLock(key: string): Promise<LockRecord | undefined>;
|
|
48
|
+
listLocks(): Promise<readonly LockRecord[]>;
|
|
49
|
+
updateLockIfCurrent(current: LockRecord | undefined, next: LockRecord): Promise<LockRecord | undefined>;
|
|
50
|
+
}
|
|
51
|
+
//#endregion
|
|
52
|
+
export { WorkflowStore, createWorkflowStore };
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { getWorkflowStoreCapabilities } from "./capabilities.mjs";
|
|
2
|
+
import { makeEventsKey } from "../store-keys.mjs";
|
|
3
|
+
import { claimWorkflowRun, countWorkflowRuns, extendWorkflowRunLease, getWorkflowRun, listWorkflowRuns, listWorkflowRunsPage, releaseWorkflowRunLease, updateRunIfCurrent, updateWorkflowRun } from "./run.mjs";
|
|
4
|
+
import { hasMessageIdempotencyKey, repairMessageIdempotencyIndexes } from "./message-index.mjs";
|
|
5
|
+
import { cleanupRuns, listCleanupMarkers } from "./cleanup.mjs";
|
|
6
|
+
import { appendWorkflowEvent, appendWorkflowEventIfRunCurrent, getWorkflowEvents } from "./event.mjs";
|
|
7
|
+
import { createRunWithIdempotency, getRunByIdempotencyKey } from "./idempotency.mjs";
|
|
8
|
+
import { getReadableLock, listReadableLocks, updateLockIfCurrent } from "./lock.mjs";
|
|
9
|
+
import { createSchedule, getReadableSchedule, listSchedules, listSchedulesPage, updateScheduleIfCurrent } from "./schedule.mjs";
|
|
10
|
+
import { countWorkflowStepAttempts, listWorkflowStepAttempts, listWorkflowStepAttemptsPage, repairWorkflowStepAttempts } from "./step-attempt.mjs";
|
|
11
|
+
import { createStorage } from "@temelj/storage";
|
|
12
|
+
//#region src/store/create.ts
|
|
13
|
+
function createWorkflowStore(options = {}) {
|
|
14
|
+
return new WorkflowStore(options);
|
|
15
|
+
}
|
|
16
|
+
/** Storage-backed workflow store implementation. */
|
|
17
|
+
var WorkflowStore = class {
|
|
18
|
+
storage;
|
|
19
|
+
namespace;
|
|
20
|
+
capabilities;
|
|
21
|
+
constructor(options = {}) {
|
|
22
|
+
this.storage = options.storage ?? createStorage();
|
|
23
|
+
this.namespace = options.namespace ?? "default";
|
|
24
|
+
this.capabilities = getWorkflowStoreCapabilities(this.storage);
|
|
25
|
+
}
|
|
26
|
+
async createRun(run) {
|
|
27
|
+
return createRunWithIdempotency(this.storage, this.namespace, this, run);
|
|
28
|
+
}
|
|
29
|
+
async getRun(runId) {
|
|
30
|
+
return getWorkflowRun(this.storage, this.namespace, runId);
|
|
31
|
+
}
|
|
32
|
+
async getRunByIdempotencyKey(options) {
|
|
33
|
+
return getRunByIdempotencyKey(this.storage, this.namespace, this, options);
|
|
34
|
+
}
|
|
35
|
+
async updateRun(run) {
|
|
36
|
+
return updateWorkflowRun(this.storage, this.namespace, this, run);
|
|
37
|
+
}
|
|
38
|
+
async updateRunIfCurrent(current, next) {
|
|
39
|
+
return updateRunIfCurrent(this.storage, this.namespace, this, current, next);
|
|
40
|
+
}
|
|
41
|
+
async listRuns(options) {
|
|
42
|
+
return listWorkflowRuns(this.storage, this.namespace, options);
|
|
43
|
+
}
|
|
44
|
+
async listRunsPage(options) {
|
|
45
|
+
return listWorkflowRunsPage(this.storage, this.namespace, options);
|
|
46
|
+
}
|
|
47
|
+
async countRuns(options) {
|
|
48
|
+
return countWorkflowRuns(this.storage, this.namespace, options);
|
|
49
|
+
}
|
|
50
|
+
async claimRun(options) {
|
|
51
|
+
return claimWorkflowRun(this.storage, this.namespace, this, options);
|
|
52
|
+
}
|
|
53
|
+
async extendRunLease(options) {
|
|
54
|
+
return extendWorkflowRunLease(this.storage, this.namespace, this, options);
|
|
55
|
+
}
|
|
56
|
+
async releaseRunLease(options) {
|
|
57
|
+
return releaseWorkflowRunLease(this.storage, this.namespace, this, options);
|
|
58
|
+
}
|
|
59
|
+
async appendEvent(runId, event) {
|
|
60
|
+
return appendWorkflowEvent(this.storage, this.namespace, runId, event);
|
|
61
|
+
}
|
|
62
|
+
async appendEventIfRunCurrent(current, event) {
|
|
63
|
+
return appendWorkflowEventIfRunCurrent(this.storage, this.namespace, current, event);
|
|
64
|
+
}
|
|
65
|
+
async getEvents(runId) {
|
|
66
|
+
return getWorkflowEvents(this.storage, this.namespace, runId);
|
|
67
|
+
}
|
|
68
|
+
async waitForEventHistoryChange(runId, options = {}) {
|
|
69
|
+
if (options.signal?.aborted === true) return;
|
|
70
|
+
const key = makeEventsKey(this.namespace, runId);
|
|
71
|
+
await new Promise((resolve) => {
|
|
72
|
+
let settled = false;
|
|
73
|
+
let unwatch;
|
|
74
|
+
const finish = () => {
|
|
75
|
+
if (settled) return;
|
|
76
|
+
settled = true;
|
|
77
|
+
options.signal?.removeEventListener("abort", finish);
|
|
78
|
+
disposeWorkflowStoreWatcher(unwatch);
|
|
79
|
+
resolve();
|
|
80
|
+
};
|
|
81
|
+
options.signal?.addEventListener("abort", finish, { once: true });
|
|
82
|
+
this.storage.watch((event) => {
|
|
83
|
+
if (isWorkflowStorageChangeForKey(event, key)) finish();
|
|
84
|
+
}).then((unsubscribe) => {
|
|
85
|
+
unwatch = unsubscribe;
|
|
86
|
+
if (settled) disposeWorkflowStoreWatcher(unwatch);
|
|
87
|
+
}).catch(() => {
|
|
88
|
+
finish();
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
async listStepAttempts(runId, options) {
|
|
93
|
+
return listWorkflowStepAttempts(this.storage, this.namespace, this, runId, options);
|
|
94
|
+
}
|
|
95
|
+
async listStepAttemptsPage(runId, options) {
|
|
96
|
+
return listWorkflowStepAttemptsPage(this.storage, this.namespace, this, runId, options);
|
|
97
|
+
}
|
|
98
|
+
async countStepAttempts(runId, options) {
|
|
99
|
+
return countWorkflowStepAttempts(this.storage, this.namespace, this, runId, options);
|
|
100
|
+
}
|
|
101
|
+
async repairStepAttempts(runId) {
|
|
102
|
+
return repairWorkflowStepAttempts(this.storage, this.namespace, this, runId);
|
|
103
|
+
}
|
|
104
|
+
async repairMessageIdempotencyIndexes(runId) {
|
|
105
|
+
return repairMessageIdempotencyIndexes(this.storage, this.namespace, runId);
|
|
106
|
+
}
|
|
107
|
+
async hasMessageIdempotencyKey(runId, idempotencyKey) {
|
|
108
|
+
return hasMessageIdempotencyKey(this.storage, this.namespace, runId, idempotencyKey);
|
|
109
|
+
}
|
|
110
|
+
async cleanupRuns(options) {
|
|
111
|
+
return cleanupRuns(this.storage, this.namespace, this, options);
|
|
112
|
+
}
|
|
113
|
+
async listCleanupMarkers() {
|
|
114
|
+
return listCleanupMarkers(this.storage, this.namespace);
|
|
115
|
+
}
|
|
116
|
+
async createSchedule(schedule) {
|
|
117
|
+
return createSchedule(this.storage, this.namespace, schedule);
|
|
118
|
+
}
|
|
119
|
+
async getSchedule(scheduleId) {
|
|
120
|
+
return getReadableSchedule(this.storage, this.namespace, scheduleId);
|
|
121
|
+
}
|
|
122
|
+
async updateScheduleIfCurrent(current, next) {
|
|
123
|
+
return updateScheduleIfCurrent(this.storage, this.namespace, current, next);
|
|
124
|
+
}
|
|
125
|
+
async listSchedules(options) {
|
|
126
|
+
return listSchedules(this.storage, this.namespace, options);
|
|
127
|
+
}
|
|
128
|
+
async listSchedulesPage(options) {
|
|
129
|
+
return listSchedulesPage(this.storage, this.namespace, options);
|
|
130
|
+
}
|
|
131
|
+
async getLock(key) {
|
|
132
|
+
return getReadableLock(this.storage, this.namespace, key);
|
|
133
|
+
}
|
|
134
|
+
async listLocks() {
|
|
135
|
+
return listReadableLocks(this.storage, this.namespace);
|
|
136
|
+
}
|
|
137
|
+
async updateLockIfCurrent(current, next) {
|
|
138
|
+
return updateLockIfCurrent(this.storage, this.namespace, current, next);
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
function disposeWorkflowStoreWatcher(unwatch) {
|
|
142
|
+
if (unwatch === void 0) return;
|
|
143
|
+
ignoreWorkflowStoreWatcherDisposal(unwatch());
|
|
144
|
+
}
|
|
145
|
+
function ignoreWorkflowStoreWatcherDisposal(result) {
|
|
146
|
+
if (result === void 0) return;
|
|
147
|
+
result.catch(() => {});
|
|
148
|
+
}
|
|
149
|
+
function isWorkflowStorageChangeForKey(event, key) {
|
|
150
|
+
switch (event.type) {
|
|
151
|
+
case "set":
|
|
152
|
+
case "delete": return event.key === key;
|
|
153
|
+
case "setMany":
|
|
154
|
+
case "deleteMany": return event.keys.includes(key);
|
|
155
|
+
case "clear": return event.prefix === void 0 || key.startsWith(event.prefix);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
//#endregion
|
|
159
|
+
export { WorkflowStore, createWorkflowStore };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { RunId } from "../types/run-id.mjs";
|
|
2
|
+
import { WorkflowRunRecord } from "../types/run.mjs";
|
|
3
|
+
import { EventRecord } from "../types/events.mjs";
|
|
4
|
+
import { WorkflowStorage } from "../types/store.mjs";
|
|
5
|
+
import { WorkflowEventAppendOutcome, WorkflowEventAppendSuccessOutcome } from "./event-append.mjs";
|
|
6
|
+
import { WorkflowAppendProjectionPipeline } from "./append-projection.mjs";
|
|
7
|
+
//#region src/store/event-append-project.d.ts
|
|
8
|
+
interface WorkflowEventAppendProjectionOutcome {
|
|
9
|
+
readonly outcome: WorkflowEventAppendOutcome;
|
|
10
|
+
readonly projectionPipeline?: WorkflowAppendProjectionPipeline;
|
|
11
|
+
}
|
|
12
|
+
declare function appendEventWithProjections(storage: WorkflowStorage, namespace: string, runId: RunId, event: EventRecord, projectionPipeline?: WorkflowAppendProjectionPipeline): Promise<WorkflowEventAppendSuccessOutcome>;
|
|
13
|
+
declare function appendEventWithProjectionPipelineIfRunCurrent(storage: WorkflowStorage, namespace: string, currentRun: WorkflowRunRecord, event: EventRecord): Promise<WorkflowEventAppendProjectionOutcome>;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { WorkflowEventAppendProjectionOutcome, appendEventWithProjectionPipelineIfRunCurrent, appendEventWithProjections };
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { supportsWorkflowAtomicBatchWrite, supportsWorkflowConditionalWrite } from "./capabilities.mjs";
|
|
2
|
+
import { isStoredWorkflowRunRevisionCurrent, isWorkflowRunStaleForAppend, rollbackAppendedEventIfRunStale } from "./run.mjs";
|
|
3
|
+
import { duplicateMessageAppendOutcome } from "./message-index.mjs";
|
|
4
|
+
import { createWorkflowAppendProjectionPipeline } from "./append-projection.mjs";
|
|
5
|
+
import { appendEventIfCurrent, appendEventIfRunRevisionCurrentAtomically, appendEventWithAtomicProjectionPlan, makeStaleRunAppendOutcome } from "./event-append.mjs";
|
|
6
|
+
//#region src/store/event-append-project.ts
|
|
7
|
+
async function appendEventWithProjections(storage, namespace, runId, event, projectionPipeline) {
|
|
8
|
+
const appendProjectionPipeline = projectionPipeline ?? await createWorkflowAppendProjectionPipeline(storage, namespace, runId, event);
|
|
9
|
+
const outcome = await appendEventWithAtomicProjectionPlan(storage, namespace, runId, event, appendProjectionPipeline.planAtomicProjections, duplicateMessageAppendOutcome);
|
|
10
|
+
await appendProjectionPipeline.finalizePostCommit(outcome);
|
|
11
|
+
return outcome;
|
|
12
|
+
}
|
|
13
|
+
async function appendEventWithProjectionPipelineIfRunCurrent(storage, namespace, currentRun, event) {
|
|
14
|
+
const runId = currentRun.id;
|
|
15
|
+
if (isWorkflowRunStaleForAppend(currentRun, event)) return { outcome: makeStaleRunAppendOutcome() };
|
|
16
|
+
const projectionPipeline = await createWorkflowAppendProjectionPipeline(storage, namespace, runId, event);
|
|
17
|
+
if (event.kind === "message_sent" && !supportsWorkflowAtomicBatchWrite(storage)) return await appendMessageEventIfRunCurrent(storage, namespace, currentRun, event, projectionPipeline);
|
|
18
|
+
if (!supportsWorkflowAtomicBatchWrite(storage) || projectionPipeline.materializesAtomically) return workflowEventAppendProjectionOutcome(await appendEventIfRunRevisionCurrentWithPostAppendGuard(storage, namespace, currentRun, event, projectionPipeline), projectionPipeline);
|
|
19
|
+
return workflowEventAppendProjectionOutcome(await appendEventIfRunRevisionCurrentAtomically(storage, namespace, currentRun, event, duplicateMessageAppendOutcome), projectionPipeline);
|
|
20
|
+
}
|
|
21
|
+
function workflowEventAppendProjectionOutcome(outcome, projectionPipeline) {
|
|
22
|
+
if (projectionPipeline === void 0) return { outcome };
|
|
23
|
+
return {
|
|
24
|
+
outcome,
|
|
25
|
+
projectionPipeline
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
async function appendEventIfRunRevisionCurrentWithPostAppendGuard(storage, namespace, currentRun, event, projectionPipeline) {
|
|
29
|
+
const runId = currentRun.id;
|
|
30
|
+
if (!await isStoredWorkflowRunRevisionCurrent(storage, namespace, currentRun)) return makeStaleRunAppendOutcome();
|
|
31
|
+
const outcome = await appendEventWithProjections(storage, namespace, runId, event, projectionPipeline);
|
|
32
|
+
if (outcome.status !== "appended") return outcome;
|
|
33
|
+
return await guardAppendedEventAgainstStaleRun(storage, namespace, runId, event, outcome);
|
|
34
|
+
}
|
|
35
|
+
async function appendMessageEventIfRunCurrent(storage, namespace, currentRun, event, projectionPipeline) {
|
|
36
|
+
const runId = currentRun.id;
|
|
37
|
+
if (!await isStoredWorkflowRunRevisionCurrent(storage, namespace, currentRun)) return { outcome: makeStaleRunAppendOutcome() };
|
|
38
|
+
if (!supportsWorkflowConditionalWrite(storage)) {
|
|
39
|
+
const outcome = await appendEventWithProjections(storage, namespace, runId, event, projectionPipeline);
|
|
40
|
+
if (outcome.status !== "appended") return {
|
|
41
|
+
outcome,
|
|
42
|
+
projectionPipeline
|
|
43
|
+
};
|
|
44
|
+
return {
|
|
45
|
+
outcome: await guardAppendedEventAgainstStaleRun(storage, namespace, runId, event, outcome),
|
|
46
|
+
projectionPipeline
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
const outcome = await appendEventIfCurrent(storage, namespace, runId, event, { detectDuplicate: duplicateMessageAppendOutcome });
|
|
50
|
+
if (outcome.status !== "appended") {
|
|
51
|
+
if (!await isStoredWorkflowRunRevisionCurrent(storage, namespace, currentRun)) return {
|
|
52
|
+
outcome: makeStaleRunAppendOutcome(),
|
|
53
|
+
projectionPipeline
|
|
54
|
+
};
|
|
55
|
+
return {
|
|
56
|
+
outcome,
|
|
57
|
+
projectionPipeline
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
if (!await isStoredWorkflowRunRevisionCurrent(storage, namespace, currentRun)) {
|
|
61
|
+
await guardAppendedEventAgainstStaleRun(storage, namespace, runId, event, outcome);
|
|
62
|
+
return {
|
|
63
|
+
outcome: makeStaleRunAppendOutcome(),
|
|
64
|
+
projectionPipeline
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
outcome: await guardAppendedEventAgainstStaleRun(storage, namespace, runId, event, outcome),
|
|
69
|
+
projectionPipeline
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
async function guardAppendedEventAgainstStaleRun(storage, namespace, runId, event, outcome) {
|
|
73
|
+
if (await rollbackAppendedEventIfRunStale(storage, namespace, runId, event, outcome.events)) return makeStaleRunAppendOutcome();
|
|
74
|
+
return outcome;
|
|
75
|
+
}
|
|
76
|
+
//#endregion
|
|
77
|
+
export { appendEventWithProjectionPipelineIfRunCurrent, appendEventWithProjections };
|