bunqueue 2.8.59 → 2.9.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 +109 -77
- package/dist/application/background/dlq.js +2 -0
- package/dist/application/contextFactory.js +5 -0
- package/dist/application/dlqManager.d.ts +11 -1
- package/dist/application/dlqManager.js +48 -10
- package/dist/application/dlqRetry.js +59 -38
- package/dist/application/eventsManager.d.ts +1 -1
- package/dist/application/eventsManager.js +30 -26
- package/dist/application/lockManager.js +1 -1
- package/dist/application/operations/jobManagement.d.ts +4 -0
- package/dist/application/operations/jobMoveOperations.js +9 -4
- package/dist/application/postgres-queue-manager/batchSnapshot.d.ts +16 -0
- package/dist/application/postgres-queue-manager/batchSnapshot.js +17 -0
- package/dist/application/postgres-queue-manager/cloud.d.ts +30 -0
- package/dist/application/postgres-queue-manager/cloud.js +55 -0
- package/dist/application/postgres-queue-manager/config.d.ts +5 -0
- package/dist/application/postgres-queue-manager/config.js +1 -0
- package/dist/application/postgres-queue-manager/control.d.ts +26 -0
- package/dist/application/postgres-queue-manager/control.js +186 -0
- package/dist/application/postgres-queue-manager/deferredWrites.d.ts +13 -0
- package/dist/application/postgres-queue-manager/deferredWrites.js +60 -0
- package/dist/application/postgres-queue-manager/delivery.d.ts +19 -0
- package/dist/application/postgres-queue-manager/delivery.js +80 -0
- package/dist/application/postgres-queue-manager/lease.d.ts +13 -0
- package/dist/application/postgres-queue-manager/lease.js +88 -0
- package/dist/application/postgres-queue-manager/lifetimeMetrics.d.ts +32 -0
- package/dist/application/postgres-queue-manager/lifetimeMetrics.js +53 -0
- package/dist/application/postgres-queue-manager/maintenance.d.ts +14 -0
- package/dist/application/postgres-queue-manager/maintenance.js +100 -0
- package/dist/application/postgres-queue-manager/operationGate.d.ts +26 -0
- package/dist/application/postgres-queue-manager/operationGate.js +96 -0
- package/dist/application/postgres-queue-manager/operations.d.ts +25 -0
- package/dist/application/postgres-queue-manager/operations.js +194 -0
- package/dist/application/postgres-queue-manager/projectionRefreshes.d.ts +43 -0
- package/dist/application/postgres-queue-manager/projectionRefreshes.js +170 -0
- package/dist/application/postgres-queue-manager/queries.d.ts +142 -0
- package/dist/application/postgres-queue-manager/queries.js +231 -0
- package/dist/application/postgres-queue-manager/relationships.d.ts +10 -0
- package/dist/application/postgres-queue-manager/relationships.js +45 -0
- package/dist/application/postgres-queue-manager/services.d.ts +31 -0
- package/dist/application/postgres-queue-manager/services.js +149 -0
- package/dist/application/postgres-queue-manager/snapshot.d.ts +51 -0
- package/dist/application/postgres-queue-manager/snapshot.js +236 -0
- package/dist/application/postgres-queue-manager/snapshotViews.d.ts +15 -0
- package/dist/application/postgres-queue-manager/snapshotViews.js +100 -0
- package/dist/application/postgres-queue-manager/startupEventBuffer.d.ts +12 -0
- package/dist/application/postgres-queue-manager/startupEventBuffer.js +36 -0
- package/dist/application/postgres-queue-manager/state.d.ts +47 -0
- package/dist/application/postgres-queue-manager/state.js +273 -0
- package/dist/application/postgres-queue-manager/terminalDelivery.d.ts +20 -0
- package/dist/application/postgres-queue-manager/terminalDelivery.js +100 -0
- package/dist/application/postgresQueueManager.d.ts +2 -0
- package/dist/application/postgresQueueManager.js +1 -0
- package/dist/application/queue-manager/ack.js +1 -1
- package/dist/application/queue-manager/delivery.js +1 -1
- package/dist/application/queue-manager/flow-failures.js +4 -0
- package/dist/application/queue-manager/limits.d.ts +2 -0
- package/dist/application/queue-manager/limits.js +4 -0
- package/dist/application/queue-manager/observability.js +15 -3
- package/dist/application/queue-manager/queries.d.ts +7 -0
- package/dist/application/queue-manager/queries.js +9 -0
- package/dist/application/queue-manager/services.d.ts +1 -1
- package/dist/application/queue-manager/services.js +4 -2
- package/dist/application/queue-manager/state.js +16 -1
- package/dist/application/statsManager.d.ts +1 -1
- package/dist/application/statsManager.js +1 -1
- package/dist/cli/commands/server.js +1 -1
- package/dist/client/events.js +2 -2
- package/dist/client/flow.js +0 -1
- package/dist/client/forwarder.d.ts +6 -4
- package/dist/client/forwarder.js +5 -3
- package/dist/client/queue/dlq.d.ts +2 -0
- package/dist/client/queue/dlq.js +14 -0
- package/dist/client/queue/dlqOps.d.ts +2 -0
- package/dist/client/queue/dlqOps.js +4 -0
- package/dist/client/queue/helpers.js +2 -0
- package/dist/client/queue/operations/add/single.js +1 -1
- package/dist/client/queue/runtime/configuration.d.ts +4 -0
- package/dist/client/queue/runtime/configuration.js +8 -0
- package/dist/client/sandboxed/runtime/state.js +2 -2
- package/dist/client/tcp/connection.d.ts +1 -1
- package/dist/client/tcp/connection.js +1 -1
- package/dist/client/tcp/runtime/state.js +2 -2
- package/dist/client/types/metrics.d.ts +1 -1
- package/dist/client/worker/runtime/control.js +0 -1
- package/dist/client/worker/runtime/execution.js +3 -8
- package/dist/client/worker/runtime/lifecycle.js +0 -1
- package/dist/client/worker/runtime/polling.d.ts +1 -0
- package/dist/client/worker/runtime/polling.js +9 -0
- package/dist/client/worker/runtime/state.js +3 -3
- package/dist/client/workflow/compensationChild.d.ts +2 -0
- package/dist/client/workflow/compensationChild.js +3 -1
- package/dist/client/workflow/compensationPass.d.ts +1 -0
- package/dist/client/workflow/compensationPass.js +18 -2
- package/dist/client/workflow/compensator.d.ts +2 -1
- package/dist/client/workflow/compensator.js +11 -3
- package/dist/client/workflow/engine.js +1 -1
- package/dist/client/workflow/executionFence.d.ts +15 -0
- package/dist/client/workflow/executionFence.js +29 -0
- package/dist/client/workflow/executor.d.ts +5 -11
- package/dist/client/workflow/executor.js +48 -47
- package/dist/client/workflow/executorLifecycle.d.ts +1 -0
- package/dist/client/workflow/executorLifecycle.js +41 -10
- package/dist/client/workflow/executorNodes.d.ts +1 -0
- package/dist/client/workflow/executorNodes.js +45 -16
- package/dist/client/workflow/executorQueue.d.ts +9 -0
- package/dist/client/workflow/executorQueue.js +15 -0
- package/dist/client/workflow/forEachRunner.d.ts +4 -0
- package/dist/client/workflow/forEachRunner.js +70 -0
- package/dist/client/workflow/loops.d.ts +4 -5
- package/dist/client/workflow/loops.js +27 -93
- package/dist/client/workflow/mapRunner.d.ts +1 -1
- package/dist/client/workflow/mapRunner.js +11 -2
- package/dist/client/workflow/recovery.d.ts +1 -0
- package/dist/client/workflow/recovery.js +24 -18
- package/dist/client/workflow/rollbackControl.d.ts +1 -0
- package/dist/client/workflow/rollbackControl.js +5 -2
- package/dist/client/workflow/runner.d.ts +3 -1
- package/dist/client/workflow/runner.js +26 -3
- package/dist/client/workflow/stepTypes.js +1 -1
- package/dist/client/workflow/subWorkflowRunner.d.ts +1 -0
- package/dist/client/workflow/subWorkflowRunner.js +7 -0
- package/dist/client/workflow/waitFor.d.ts +4 -0
- package/dist/client/workflow/waitFor.js +23 -11
- package/dist/client/workflow/workflowDecisions.d.ts +1 -1
- package/dist/client/workflow/workflowDecisions.js +3 -1
- package/dist/config/resolve.d.ts +14 -0
- package/dist/config/resolve.js +50 -5
- package/dist/config/types.d.ts +18 -0
- package/dist/domain/queue/dlqShard.d.ts +2 -0
- package/dist/domain/queue/dlqShard.js +16 -0
- package/dist/domain/queue/shard/dlq.d.ts +1 -0
- package/dist/domain/queue/shard/dlq.js +3 -0
- package/dist/domain/types/commands/dlq.d.ts +5 -0
- package/dist/domain/types/commands/union.d.ts +1 -1
- package/dist/domain/types/cron.d.ts +5 -0
- package/dist/domain/types/cron.js +14 -3
- package/dist/domain/types/dlq.d.ts +1 -1
- package/dist/domain/types/dlq.js +1 -2
- package/dist/domain/types/jobs/model.d.ts +1 -1
- package/dist/infrastructure/cloud/commandHandler.js +5 -3
- package/dist/infrastructure/cloud/commands/integrations.js +11 -11
- package/dist/infrastructure/cloud/commands/jobs.js +48 -40
- package/dist/infrastructure/cloud/commands/queues.js +61 -75
- package/dist/infrastructure/cloud/queueAdapter/local.d.ts +41 -0
- package/dist/infrastructure/cloud/queueAdapter/local.js +187 -0
- package/dist/infrastructure/cloud/queueAdapter/postgres.d.ts +42 -0
- package/dist/infrastructure/cloud/queueAdapter/postgres.js +188 -0
- package/dist/infrastructure/cloud/queueAdapter/registry.d.ts +4 -0
- package/dist/infrastructure/cloud/queueAdapter/registry.js +15 -0
- package/dist/infrastructure/cloud/queueAdapter/types.d.ts +87 -0
- package/dist/infrastructure/cloud/queueAdapter/types.js +1 -0
- package/dist/infrastructure/cloud/snapshot/analytics.d.ts +2 -0
- package/dist/infrastructure/cloud/snapshot/analytics.js +7 -0
- package/dist/infrastructure/cloud/snapshot/collector.d.ts +4 -0
- package/dist/infrastructure/cloud/snapshot/collector.js +39 -1
- package/dist/infrastructure/cloud/snapshot/config.d.ts +3 -0
- package/dist/infrastructure/cloud/snapshot/config.js +43 -0
- package/dist/infrastructure/cloud/snapshot/jobs.d.ts +3 -0
- package/dist/infrastructure/cloud/snapshot/jobs.js +32 -1
- package/dist/infrastructure/cloud/snapshotCollector.js +20 -35
- package/dist/infrastructure/cloud/snapshotHelpers.d.ts +3 -3
- package/dist/infrastructure/cloud/snapshotHelpers.js +3 -3
- package/dist/infrastructure/cloud/statsRefresh.js +2 -1
- package/dist/infrastructure/cloud/types/command.d.ts +2 -2
- package/dist/infrastructure/persistence/postgres/admission.d.ts +18 -0
- package/dist/infrastructure/persistence/postgres/admission.js +193 -0
- package/dist/infrastructure/persistence/postgres/admissionParent.d.ts +5 -0
- package/dist/infrastructure/persistence/postgres/admissionParent.js +35 -0
- package/dist/infrastructure/persistence/postgres/admissionResult.d.ts +9 -0
- package/dist/infrastructure/persistence/postgres/admissionResult.js +1 -0
- package/dist/infrastructure/persistence/postgres/admissionStore.d.ts +12 -0
- package/dist/infrastructure/persistence/postgres/admissionStore.js +101 -0
- package/dist/infrastructure/persistence/postgres/advisoryLocks.d.ts +2 -0
- package/dist/infrastructure/persistence/postgres/advisoryLocks.js +13 -0
- package/dist/infrastructure/persistence/postgres/batchAdmission.d.ts +11 -0
- package/dist/infrastructure/persistence/postgres/batchAdmission.js +110 -0
- package/dist/infrastructure/persistence/postgres/batchCompletion.d.ts +4 -0
- package/dist/infrastructure/persistence/postgres/batchCompletion.js +174 -0
- package/dist/infrastructure/persistence/postgres/batchEvents.d.ts +14 -0
- package/dist/infrastructure/persistence/postgres/batchEvents.js +72 -0
- package/dist/infrastructure/persistence/postgres/brokerSessions.d.ts +14 -0
- package/dist/infrastructure/persistence/postgres/brokerSessions.js +94 -0
- package/dist/infrastructure/persistence/postgres/claimBatch.d.ts +11 -0
- package/dist/infrastructure/persistence/postgres/claimBatch.js +56 -0
- package/dist/infrastructure/persistence/postgres/claimSelection.d.ts +4 -0
- package/dist/infrastructure/persistence/postgres/claimSelection.js +198 -0
- package/dist/infrastructure/persistence/postgres/claims.d.ts +3 -0
- package/dist/infrastructure/persistence/postgres/claims.js +137 -0
- package/dist/infrastructure/persistence/postgres/cloudReadModel.d.ts +26 -0
- package/dist/infrastructure/persistence/postgres/cloudReadModel.js +123 -0
- package/dist/infrastructure/persistence/postgres/codec.d.ts +30 -0
- package/dist/infrastructure/persistence/postgres/codec.js +82 -0
- package/dist/infrastructure/persistence/postgres/completionEvents.d.ts +11 -0
- package/dist/infrastructure/persistence/postgres/completionEvents.js +21 -0
- package/dist/infrastructure/persistence/postgres/completionLifecycle.d.ts +11 -0
- package/dist/infrastructure/persistence/postgres/completionLifecycle.js +145 -0
- package/dist/infrastructure/persistence/postgres/completionOutcome.d.ts +4 -0
- package/dist/infrastructure/persistence/postgres/completionOutcome.js +112 -0
- package/dist/infrastructure/persistence/postgres/completionQueries.d.ts +10 -0
- package/dist/infrastructure/persistence/postgres/completionQueries.js +87 -0
- package/dist/infrastructure/persistence/postgres/connection.d.ts +3 -0
- package/dist/infrastructure/persistence/postgres/connection.js +15 -0
- package/dist/infrastructure/persistence/postgres/context.d.ts +28 -0
- package/dist/infrastructure/persistence/postgres/context.js +74 -0
- package/dist/infrastructure/persistence/postgres/control.d.ts +23 -0
- package/dist/infrastructure/persistence/postgres/control.js +105 -0
- package/dist/infrastructure/persistence/postgres/crons.d.ts +18 -0
- package/dist/infrastructure/persistence/postgres/crons.js +205 -0
- package/dist/infrastructure/persistence/postgres/deduplication.d.ts +9 -0
- package/dist/infrastructure/persistence/postgres/deduplication.js +47 -0
- package/dist/infrastructure/persistence/postgres/dependencyDestruction.d.ts +14 -0
- package/dist/infrastructure/persistence/postgres/dependencyDestruction.js +74 -0
- package/dist/infrastructure/persistence/postgres/dependencyPromotion.d.ts +29 -0
- package/dist/infrastructure/persistence/postgres/dependencyPromotion.js +212 -0
- package/dist/infrastructure/persistence/postgres/destructiveMutations.d.ts +4 -0
- package/dist/infrastructure/persistence/postgres/destructiveMutations.js +111 -0
- package/dist/infrastructure/persistence/postgres/dlqLifecycle.d.ts +13 -0
- package/dist/infrastructure/persistence/postgres/dlqLifecycle.js +184 -0
- package/dist/infrastructure/persistence/postgres/dlqMaintenance.d.ts +6 -0
- package/dist/infrastructure/persistence/postgres/dlqMaintenance.js +36 -0
- package/dist/infrastructure/persistence/postgres/dlqRetryPlan.d.ts +21 -0
- package/dist/infrastructure/persistence/postgres/dlqRetryPlan.js +92 -0
- package/dist/infrastructure/persistence/postgres/eventCommitGc.d.ts +27 -0
- package/dist/infrastructure/persistence/postgres/eventCommitGc.js +62 -0
- package/dist/infrastructure/persistence/postgres/eventJournal.d.ts +18 -0
- package/dist/infrastructure/persistence/postgres/eventJournal.js +76 -0
- package/dist/infrastructure/persistence/postgres/eventJournalSchema.d.ts +5 -0
- package/dist/infrastructure/persistence/postgres/eventJournalSchema.js +253 -0
- package/dist/infrastructure/persistence/postgres/eventPruneWatermarks.d.ts +24 -0
- package/dist/infrastructure/persistence/postgres/eventPruneWatermarks.js +111 -0
- package/dist/infrastructure/persistence/postgres/eventRetention.d.ts +18 -0
- package/dist/infrastructure/persistence/postgres/eventRetention.js +76 -0
- package/dist/infrastructure/persistence/postgres/events.d.ts +45 -0
- package/dist/infrastructure/persistence/postgres/events.js +249 -0
- package/dist/infrastructure/persistence/postgres/expiry.d.ts +3 -0
- package/dist/infrastructure/persistence/postgres/expiry.js +74 -0
- package/dist/infrastructure/persistence/postgres/flowFailures.d.ts +17 -0
- package/dist/infrastructure/persistence/postgres/flowFailures.js +199 -0
- package/dist/infrastructure/persistence/postgres/jobData.d.ts +3 -0
- package/dist/infrastructure/persistence/postgres/jobData.js +32 -0
- package/dist/infrastructure/persistence/postgres/leaseRelease.d.ts +9 -0
- package/dist/infrastructure/persistence/postgres/leaseRelease.js +120 -0
- package/dist/infrastructure/persistence/postgres/leaseRenewal.d.ts +4 -0
- package/dist/infrastructure/persistence/postgres/leaseRenewal.js +35 -0
- package/dist/infrastructure/persistence/postgres/lifetimeMetrics.d.ts +15 -0
- package/dist/infrastructure/persistence/postgres/lifetimeMetrics.js +46 -0
- package/dist/infrastructure/persistence/postgres/lifetimeMetricsFinalizer.d.ts +4 -0
- package/dist/infrastructure/persistence/postgres/lifetimeMetricsFinalizer.js +13 -0
- package/dist/infrastructure/persistence/postgres/logs.d.ts +6 -0
- package/dist/infrastructure/persistence/postgres/logs.js +70 -0
- package/dist/infrastructure/persistence/postgres/maintenance.d.ts +6 -0
- package/dist/infrastructure/persistence/postgres/maintenance.js +138 -0
- package/dist/infrastructure/persistence/postgres/maintenanceFlights.d.ts +14 -0
- package/dist/infrastructure/persistence/postgres/maintenanceFlights.js +66 -0
- package/dist/infrastructure/persistence/postgres/metricWrites.d.ts +9 -0
- package/dist/infrastructure/persistence/postgres/metricWrites.js +94 -0
- package/dist/infrastructure/persistence/postgres/mutations.d.ts +9 -0
- package/dist/infrastructure/persistence/postgres/mutations.js +171 -0
- package/dist/infrastructure/persistence/postgres/outcomes.d.ts +4 -0
- package/dist/infrastructure/persistence/postgres/outcomes.js +194 -0
- package/dist/infrastructure/persistence/postgres/policies.d.ts +11 -0
- package/dist/infrastructure/persistence/postgres/policies.js +18 -0
- package/dist/infrastructure/persistence/postgres/postCommitMaintenance.d.ts +17 -0
- package/dist/infrastructure/persistence/postgres/postCommitMaintenance.js +117 -0
- package/dist/infrastructure/persistence/postgres/promotion.d.ts +3 -0
- package/dist/infrastructure/persistence/postgres/promotion.js +43 -0
- package/dist/infrastructure/persistence/postgres/queries.d.ts +22 -0
- package/dist/infrastructure/persistence/postgres/queries.js +152 -0
- package/dist/infrastructure/persistence/postgres/queueDestruction.d.ts +3 -0
- package/dist/infrastructure/persistence/postgres/queueDestruction.js +154 -0
- package/dist/infrastructure/persistence/postgres/queueLifecycle.d.ts +10 -0
- package/dist/infrastructure/persistence/postgres/queueLifecycle.js +60 -0
- package/dist/infrastructure/persistence/postgres/rateLimit.d.ts +6 -0
- package/dist/infrastructure/persistence/postgres/rateLimit.js +10 -0
- package/dist/infrastructure/persistence/postgres/readModels.d.ts +32 -0
- package/dist/infrastructure/persistence/postgres/readModels.js +72 -0
- package/dist/infrastructure/persistence/postgres/recovery.d.ts +3 -0
- package/dist/infrastructure/persistence/postgres/recovery.js +178 -0
- package/dist/infrastructure/persistence/postgres/relationships.d.ts +9 -0
- package/dist/infrastructure/persistence/postgres/relationships.js +201 -0
- package/dist/infrastructure/persistence/postgres/removeUnprocessedChildren.d.ts +4 -0
- package/dist/infrastructure/persistence/postgres/removeUnprocessedChildren.js +241 -0
- package/dist/infrastructure/persistence/postgres/repeatMutations.d.ts +5 -0
- package/dist/infrastructure/persistence/postgres/repeatMutations.js +37 -0
- package/dist/infrastructure/persistence/postgres/runtime.d.ts +46 -0
- package/dist/infrastructure/persistence/postgres/runtime.js +236 -0
- package/dist/infrastructure/persistence/postgres/runtimeConfig.d.ts +21 -0
- package/dist/infrastructure/persistence/postgres/runtimeConfig.js +39 -0
- package/dist/infrastructure/persistence/postgres/schema.d.ts +4 -0
- package/dist/infrastructure/persistence/postgres/schema.js +257 -0
- package/dist/infrastructure/persistence/postgres/schemaInitialization.d.ts +3 -0
- package/dist/infrastructure/persistence/postgres/schemaInitialization.js +221 -0
- package/dist/infrastructure/persistence/postgres/serialAdmission.d.ts +6 -0
- package/dist/infrastructure/persistence/postgres/serialAdmission.js +96 -0
- package/dist/infrastructure/persistence/postgres/snapshotBudget.d.ts +3 -0
- package/dist/infrastructure/persistence/postgres/snapshotBudget.js +83 -0
- package/dist/infrastructure/persistence/postgres/storageHealth.d.ts +10 -0
- package/dist/infrastructure/persistence/postgres/storageHealth.js +29 -0
- package/dist/infrastructure/persistence/postgres/store.d.ts +90 -0
- package/dist/infrastructure/persistence/postgres/store.js +136 -0
- package/dist/infrastructure/persistence/postgres/telemetry.d.ts +6 -0
- package/dist/infrastructure/persistence/postgres/telemetry.js +88 -0
- package/dist/infrastructure/persistence/postgres/terminal.d.ts +8 -0
- package/dist/infrastructure/persistence/postgres/terminal.js +137 -0
- package/dist/infrastructure/persistence/postgres/transactionRetry.d.ts +6 -0
- package/dist/infrastructure/persistence/postgres/transactionRetry.js +42 -0
- package/dist/infrastructure/persistence/postgres/types.d.ts +175 -0
- package/dist/infrastructure/persistence/postgres/types.js +1 -0
- package/dist/infrastructure/persistence/postgres/workers.d.ts +15 -0
- package/dist/infrastructure/persistence/postgres/workers.js +126 -0
- package/dist/infrastructure/persistence/postgres.d.ts +2 -0
- package/dist/infrastructure/persistence/postgres.js +1 -0
- package/dist/infrastructure/persistence/sqlite/jobs.js +2 -0
- package/dist/infrastructure/persistence/sqlite.d.ts +1 -1
- package/dist/infrastructure/scheduler/cron/persisted.d.ts +5 -0
- package/dist/infrastructure/scheduler/cron/persisted.js +27 -0
- package/dist/infrastructure/scheduler/cron/runtime.js +5 -10
- package/dist/infrastructure/scheduler/cron/validation.d.ts +3 -0
- package/dist/infrastructure/scheduler/cron/validation.js +11 -0
- package/dist/infrastructure/scheduler/cronParser.d.ts +1 -1
- package/dist/infrastructure/scheduler/cronParser.js +144 -11
- package/dist/infrastructure/server/bootstrap.d.ts +2 -3
- package/dist/infrastructure/server/bootstrap.js +33 -59
- package/dist/infrastructure/server/errors.d.ts +4 -0
- package/dist/infrastructure/server/errors.js +54 -0
- package/dist/infrastructure/server/handler-routes/control.d.ts +5 -5
- package/dist/infrastructure/server/handler-routes/control.js +3 -1
- package/dist/infrastructure/server/handler-routes/jobs.js +0 -3
- package/dist/infrastructure/server/handler-routes/monitoring.d.ts +2 -2
- package/dist/infrastructure/server/handler.js +9 -11
- package/dist/infrastructure/server/handlerRoutes.d.ts +2 -2
- package/dist/infrastructure/server/handlerRoutes.js +2 -2
- package/dist/infrastructure/server/handlers/advanced/dependencies.js +7 -6
- package/dist/infrastructure/server/handlers/advanced/jobs.js +19 -6
- package/dist/infrastructure/server/handlers/advanced/queue.d.ts +9 -9
- package/dist/infrastructure/server/handlers/advanced/queue.js +91 -27
- package/dist/infrastructure/server/handlers/core.js +32 -31
- package/dist/infrastructure/server/handlers/cron.d.ts +4 -4
- package/dist/infrastructure/server/handlers/cron.js +60 -59
- package/dist/infrastructure/server/handlers/dashboard.d.ts +1 -1
- package/dist/infrastructure/server/handlers/dashboard.js +21 -8
- package/dist/infrastructure/server/handlers/dlq.d.ts +6 -3
- package/dist/infrastructure/server/handlers/dlq.js +35 -9
- package/dist/infrastructure/server/handlers/flow.js +2 -1
- package/dist/infrastructure/server/handlers/management.d.ts +5 -5
- package/dist/infrastructure/server/handlers/management.js +36 -9
- package/dist/infrastructure/server/handlers/monitoring/health.d.ts +5 -5
- package/dist/infrastructure/server/handlers/monitoring/health.js +45 -16
- package/dist/infrastructure/server/handlers/monitoring/operations.d.ts +1 -1
- package/dist/infrastructure/server/handlers/monitoring/operations.js +8 -1
- package/dist/infrastructure/server/handlers/monitoring/workers.d.ts +3 -3
- package/dist/infrastructure/server/handlers/monitoring/workers.js +31 -7
- package/dist/infrastructure/server/handlers/pushBatchValidation.d.ts +3 -1
- package/dist/infrastructure/server/handlers/pushBatchValidation.js +52 -7
- package/dist/infrastructure/server/handlers/query.d.ts +1 -1
- package/dist/infrastructure/server/handlers/query.js +5 -4
- package/dist/infrastructure/server/http.js +2 -2
- package/dist/infrastructure/server/httpDashboardEndpoints.d.ts +1 -1
- package/dist/infrastructure/server/httpDashboardEndpoints.js +19 -6
- package/dist/infrastructure/server/httpEndpoints.js +20 -7
- package/dist/infrastructure/server/httpRouteQueues.js +11 -1
- package/dist/infrastructure/server/shutdownCoordinator.d.ts +24 -0
- package/dist/infrastructure/server/shutdownCoordinator.js +106 -0
- package/dist/infrastructure/server/sseHandler.js +8 -3
- package/dist/infrastructure/server/storageAdapter.d.ts +29 -0
- package/dist/infrastructure/server/storageAdapter.js +61 -0
- package/dist/infrastructure/server/storageManager.d.ts +12 -0
- package/dist/infrastructure/server/storageManager.js +102 -0
- package/dist/infrastructure/server/tcp.js +2 -3
- package/dist/infrastructure/server/ws/snapshots.d.ts +1 -1
- package/dist/infrastructure/server/ws/snapshots.js +19 -4
- package/dist/infrastructure/server/wsHandler.js +10 -5
- package/dist/main.js +1 -1
- package/dist/mcp/backend/embedded/services.js +2 -1
- package/dist/mcp/index.d.ts +2 -2
- package/dist/mcp/index.js +2 -2
- package/dist/shared/storageHealth.d.ts +9 -0
- package/dist/shared/storageHealth.js +12 -0
- package/package.json +85 -74
|
@@ -5,11 +5,13 @@
|
|
|
5
5
|
* The edge pattern: jobs buffer in the local queue (typically embedded
|
|
6
6
|
* SQLite on a gateway); the Forwarder drains them to a central server over
|
|
7
7
|
* TCP/TLS. A remote failure makes the local job fail → local retry/backoff →
|
|
8
|
-
* local DLQ
|
|
8
|
+
* local DLQ. With a persistent local `dataPath`, queued work survives uplink
|
|
9
|
+
* outages and process restarts; memory-only sources provide no such guarantee.
|
|
9
10
|
*
|
|
10
11
|
* Idempotency: every forwarded job carries the deterministic remote jobId
|
|
11
|
-
* `fwd:<localQueueKey>:<localJobId>`. The server dedupes custom jobIds
|
|
12
|
-
*
|
|
12
|
+
* `fwd:<localQueueKey>:<localJobId>`. The server dedupes custom jobIds while
|
|
13
|
+
* their ownership is retained; after bounded retention or removal, downstream
|
|
14
|
+
* effects must still tolerate at-least-once delivery.
|
|
13
15
|
*/
|
|
14
16
|
import { EventEmitter } from 'events';
|
|
15
17
|
import type { ConnectionOptions, QueueOptions } from './types';
|
|
@@ -21,7 +23,7 @@ export interface ForwardOptions {
|
|
|
21
23
|
queue?: string;
|
|
22
24
|
/** Parallel forwards (default: 4) */
|
|
23
25
|
concurrency?: number;
|
|
24
|
-
/** Push
|
|
26
|
+
/** Push with durable: true (bypasses SQLite buffering; PostgreSQL is already transactional). */
|
|
25
27
|
durable?: boolean;
|
|
26
28
|
}
|
|
27
29
|
/** Source queue identity + config, provided by Queue.forward() */
|
package/dist/client/forwarder.js
CHANGED
|
@@ -5,11 +5,13 @@
|
|
|
5
5
|
* The edge pattern: jobs buffer in the local queue (typically embedded
|
|
6
6
|
* SQLite on a gateway); the Forwarder drains them to a central server over
|
|
7
7
|
* TCP/TLS. A remote failure makes the local job fail → local retry/backoff →
|
|
8
|
-
* local DLQ
|
|
8
|
+
* local DLQ. With a persistent local `dataPath`, queued work survives uplink
|
|
9
|
+
* outages and process restarts; memory-only sources provide no such guarantee.
|
|
9
10
|
*
|
|
10
11
|
* Idempotency: every forwarded job carries the deterministic remote jobId
|
|
11
|
-
* `fwd:<localQueueKey>:<localJobId>`. The server dedupes custom jobIds
|
|
12
|
-
*
|
|
12
|
+
* `fwd:<localQueueKey>:<localJobId>`. The server dedupes custom jobIds while
|
|
13
|
+
* their ownership is retained; after bounded retention or removal, downstream
|
|
14
|
+
* effects must still tolerate at-least-once delivery.
|
|
13
15
|
*/
|
|
14
16
|
import { EventEmitter } from 'events';
|
|
15
17
|
import { Worker } from './worker';
|
|
@@ -52,6 +52,8 @@ export declare function purgeDlq(ctx: DlqContext): number;
|
|
|
52
52
|
* purge-then-assert-empty patterns need this variant.
|
|
53
53
|
*/
|
|
54
54
|
export declare function purgeDlqAsync(ctx: DlqContext): Promise<number>;
|
|
55
|
+
/** Remove one DLQ entry without re-enqueuing it. */
|
|
56
|
+
export declare function removeDlqJobAsync(ctx: DlqContext, id: string): Promise<boolean>;
|
|
55
57
|
/** Retry completed job */
|
|
56
58
|
export declare function retryCompleted(ctx: DlqContext, id?: string): number;
|
|
57
59
|
/** Retry completed job (async) */
|
package/dist/client/queue/dlq.js
CHANGED
|
@@ -197,6 +197,20 @@ export async function purgeDlqAsync(ctx) {
|
|
|
197
197
|
return 0;
|
|
198
198
|
return (response.count ?? 0);
|
|
199
199
|
}
|
|
200
|
+
/** Remove one DLQ entry without re-enqueuing it. */
|
|
201
|
+
export async function removeDlqJobAsync(ctx, id) {
|
|
202
|
+
if (ctx.embedded)
|
|
203
|
+
return dlqOps.removeDlqJobEmbedded(ctx.name, id);
|
|
204
|
+
if (!ctx.tcp)
|
|
205
|
+
return false;
|
|
206
|
+
const response = await ctx.tcp.send({ cmd: 'RemoveDlqJob', queue: ctx.name, jobId: id });
|
|
207
|
+
if (!response.ok) {
|
|
208
|
+
const error = typeof response.error === 'string' ? response.error : 'Failed to remove the DLQ job';
|
|
209
|
+
throw new Error(error);
|
|
210
|
+
}
|
|
211
|
+
const payload = response;
|
|
212
|
+
return payload.data?.removed === true;
|
|
213
|
+
}
|
|
200
214
|
/** Retry completed job */
|
|
201
215
|
export function retryCompleted(ctx, id) {
|
|
202
216
|
if (ctx.embedded) {
|
|
@@ -18,6 +18,8 @@ export declare function retryDlqByFilterEmbedded(queue: string, filter: DlqFilte
|
|
|
18
18
|
export declare function retryDlqEmbedded(queue: string, id?: string): number;
|
|
19
19
|
/** Purge DLQ (embedded) */
|
|
20
20
|
export declare function purgeDlqEmbedded(queue: string): number;
|
|
21
|
+
/** Remove one DLQ entry in embedded mode. */
|
|
22
|
+
export declare function removeDlqJobEmbedded(queue: string, id: string): boolean;
|
|
21
23
|
/** Set stall config (embedded only) */
|
|
22
24
|
export declare function setStallConfigEmbedded(queue: string, config: Record<string, unknown>): void;
|
|
23
25
|
/** Get stall config (embedded only) */
|
|
@@ -50,6 +50,10 @@ export function retryDlqEmbedded(queue, id) {
|
|
|
50
50
|
export function purgeDlqEmbedded(queue) {
|
|
51
51
|
return getSharedManager().purgeDlq(queue);
|
|
52
52
|
}
|
|
53
|
+
/** Remove one DLQ entry in embedded mode. */
|
|
54
|
+
export function removeDlqJobEmbedded(queue, id) {
|
|
55
|
+
return getSharedManager().removeDlqJob(queue, jobId(id));
|
|
56
|
+
}
|
|
53
57
|
/** Set stall config (embedded only) */
|
|
54
58
|
export function setStallConfigEmbedded(queue, config) {
|
|
55
59
|
const manager = getSharedManager();
|
|
@@ -20,6 +20,8 @@ export function getDlqContext(manager) {
|
|
|
20
20
|
shards: getShards(manager),
|
|
21
21
|
jobIndex: manager.getJobIndex(),
|
|
22
22
|
jobResults: manager.jobResults,
|
|
23
|
+
dependencyResults: manager.dependencyResults,
|
|
24
|
+
customIdMap: manager.customIdMap,
|
|
23
25
|
jobLogs: manager.jobLogs,
|
|
24
26
|
// #110-class: without storage, retryDlqByFilter's deleteDlqEntry/insertJob
|
|
25
27
|
// silently no-op — filtered retries were never persisted in embedded mode
|
|
@@ -57,7 +57,7 @@ export async function add(context, jobName, data, options = {}) {
|
|
|
57
57
|
updateProgress: async (id, progress, message) => {
|
|
58
58
|
await manager.updateProgress(jobId(id), progress, message);
|
|
59
59
|
},
|
|
60
|
-
//
|
|
60
|
+
// oxlint-disable-next-line typescript/require-await -- public callback contract is asynchronous
|
|
61
61
|
log: async (id, message) => {
|
|
62
62
|
manager.addLog(jobId(id), message);
|
|
63
63
|
},
|
|
@@ -21,6 +21,10 @@ export declare class QueueConfiguration<T> extends QueueControl<T> {
|
|
|
21
21
|
retryDlqByFilterAsync(filter: DlqFilter): Promise<number>;
|
|
22
22
|
purgeDlq(): number;
|
|
23
23
|
purgeDlqAsync(): Promise<number>;
|
|
24
|
+
/** Remove one DLQ entry and resolve when the removal completes. */
|
|
25
|
+
removeDlqJob(id: string): Promise<boolean>;
|
|
26
|
+
/** Explicit async alias for removeDlqJob. */
|
|
27
|
+
removeDlqJobAsync(id: string): Promise<boolean>;
|
|
24
28
|
retryCompleted(id?: string): number;
|
|
25
29
|
retryCompletedAsync(id?: string): Promise<number>;
|
|
26
30
|
setGlobalConcurrency(concurrency: number): void;
|
|
@@ -61,6 +61,14 @@ export class QueueConfiguration extends QueueControl {
|
|
|
61
61
|
purgeDlqAsync() {
|
|
62
62
|
return dlqOps.purgeDlqAsync(this.ctx);
|
|
63
63
|
}
|
|
64
|
+
/** Remove one DLQ entry and resolve when the removal completes. */
|
|
65
|
+
removeDlqJob(id) {
|
|
66
|
+
return dlqOps.removeDlqJobAsync(this.ctx, id);
|
|
67
|
+
}
|
|
68
|
+
/** Explicit async alias for removeDlqJob. */
|
|
69
|
+
removeDlqJobAsync(id) {
|
|
70
|
+
return this.removeDlqJob(id);
|
|
71
|
+
}
|
|
64
72
|
retryCompleted(id) {
|
|
65
73
|
return dlqOps.retryCompleted(this.ctx, id);
|
|
66
74
|
}
|
|
@@ -3,11 +3,11 @@ import { getSharedManager } from '../../manager';
|
|
|
3
3
|
import { getSharedPool } from '../../tcpPool';
|
|
4
4
|
import { createEmbeddedOps, createTcpOps } from '../queueOps';
|
|
5
5
|
export class SandboxedState extends EventEmitter {
|
|
6
|
-
//
|
|
6
|
+
// oxlint-disable-next-line typescript/no-explicit-any -- EventEmitter's fallback listener is intentionally untyped
|
|
7
7
|
on(event, listener) {
|
|
8
8
|
return super.on(event, listener);
|
|
9
9
|
}
|
|
10
|
-
//
|
|
10
|
+
// oxlint-disable-next-line typescript/no-explicit-any -- EventEmitter's fallback listener is intentionally untyped
|
|
11
11
|
once(event, listener) {
|
|
12
12
|
return super.once(event, listener);
|
|
13
13
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
/** Stable low-level TCP connection import surface. */
|
|
2
2
|
export { CommandQueue } from './commandQueue';
|
|
3
|
-
export { buildClientTls, createConnection, tlsRequiresVerification
|
|
3
|
+
export { buildClientTls, createConnection, tlsRequiresVerification } from './transport';
|
|
4
4
|
export type { ConnectionEvents, ConnectionResult, ConnectionTarget } from './transport';
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
/** Stable low-level TCP connection import surface. */
|
|
2
2
|
export { CommandQueue } from './commandQueue';
|
|
3
|
-
export { buildClientTls, createConnection, tlsRequiresVerification
|
|
3
|
+
export { buildClientTls, createConnection, tlsRequiresVerification } from './transport';
|
|
@@ -5,11 +5,11 @@ import { ReconnectManager } from '../reconnect';
|
|
|
5
5
|
import { DEFAULT_CONNECTION } from '../types';
|
|
6
6
|
/** Shared TCP client state and event contract. */
|
|
7
7
|
export class TcpClientState extends EventEmitter {
|
|
8
|
-
//
|
|
8
|
+
// oxlint-disable-next-line typescript/no-explicit-any -- EventEmitter's fallback overload requires any[]
|
|
9
9
|
on(event, listener) {
|
|
10
10
|
return super.on(event, listener);
|
|
11
11
|
}
|
|
12
|
-
//
|
|
12
|
+
// oxlint-disable-next-line typescript/no-explicit-any -- EventEmitter's fallback overload requires any[]
|
|
13
13
|
once(event, listener) {
|
|
14
14
|
return super.once(event, listener);
|
|
15
15
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export type { QueueMetrics, QueueMetricsMeta, QueueMetricType
|
|
1
|
+
export type { QueueMetrics, QueueMetricsMeta, QueueMetricType } from '../../domain/types/metrics';
|
|
@@ -152,7 +152,6 @@ export class WorkerControl extends WorkerState {
|
|
|
152
152
|
async startStalledCheckTimer() {
|
|
153
153
|
// No-op for API compatibility; stall detection is automatic.
|
|
154
154
|
}
|
|
155
|
-
// biome-ignore lint/suspicious/useAwait: public compatibility contract is asynchronous
|
|
156
155
|
async delay(milliseconds = 0, abortController) {
|
|
157
156
|
if (milliseconds <= 0)
|
|
158
157
|
return;
|
|
@@ -39,15 +39,10 @@ export class WorkerExecution extends WorkerPolling {
|
|
|
39
39
|
if (this.groupLimiter)
|
|
40
40
|
this.groupLimiter.decrement(job);
|
|
41
41
|
if (this.running && !this._closing)
|
|
42
|
-
this.
|
|
42
|
+
this.scheduleProcessing();
|
|
43
43
|
});
|
|
44
|
-
if (this.activeJobs < this.opts.concurrency && !this._closing
|
|
45
|
-
this.
|
|
46
|
-
setImmediate(() => {
|
|
47
|
-
this.processingScheduled = false;
|
|
48
|
-
void this.tryProcess();
|
|
49
|
-
});
|
|
50
|
-
}
|
|
44
|
+
if (this.activeJobs < this.opts.concurrency && !this._closing)
|
|
45
|
+
this.scheduleProcessing();
|
|
51
46
|
return true;
|
|
52
47
|
}
|
|
53
48
|
registerWithServer() {
|
|
@@ -2,7 +2,6 @@ import { jobId } from '../../../domain/types/job';
|
|
|
2
2
|
import { getSharedManager } from '../../manager';
|
|
3
3
|
import { WorkerManual } from './manual';
|
|
4
4
|
export class WorkerLifecycle extends WorkerManual {
|
|
5
|
-
// biome-ignore lint/suspicious/useAwait: preserves the public async close contract
|
|
6
5
|
async close(force = false) {
|
|
7
6
|
if (this.closed)
|
|
8
7
|
return;
|
|
@@ -3,6 +3,7 @@ import { WorkerBuffer } from './buffer';
|
|
|
3
3
|
import type { PulledJob, WorkerDelivery } from './state';
|
|
4
4
|
export declare abstract class WorkerPolling<T = unknown, R = unknown> extends WorkerBuffer<T, R> {
|
|
5
5
|
protected poll(): void;
|
|
6
|
+
protected scheduleProcessing(): void;
|
|
6
7
|
protected tryProcess(): Promise<void>;
|
|
7
8
|
protected doPullBatch(): Promise<PulledJob[]>;
|
|
8
9
|
private scheduleRateLimitPoll;
|
|
@@ -16,6 +16,15 @@ export class WorkerPolling extends WorkerBuffer {
|
|
|
16
16
|
}
|
|
17
17
|
void this.tryProcess();
|
|
18
18
|
}
|
|
19
|
+
scheduleProcessing() {
|
|
20
|
+
if (!this.running || this._closing || this.processingScheduled)
|
|
21
|
+
return;
|
|
22
|
+
this.processingScheduled = true;
|
|
23
|
+
setImmediate(() => {
|
|
24
|
+
this.processingScheduled = false;
|
|
25
|
+
void this.tryProcess();
|
|
26
|
+
});
|
|
27
|
+
}
|
|
19
28
|
async tryProcess() {
|
|
20
29
|
if (!this.running || this._closing)
|
|
21
30
|
return;
|
|
@@ -46,15 +46,15 @@ export class WorkerState extends EventEmitter {
|
|
|
46
46
|
lastDrainedEmit = 0;
|
|
47
47
|
stalledUnsubscribe = null;
|
|
48
48
|
stalledSubscription = null;
|
|
49
|
-
//
|
|
49
|
+
// oxlint-disable-next-line typescript/no-explicit-any -- EventEmitter's fallback listener is intentionally untyped
|
|
50
50
|
on(event, listener) {
|
|
51
51
|
return super.on(event, listener);
|
|
52
52
|
}
|
|
53
|
-
//
|
|
53
|
+
// oxlint-disable-next-line typescript/no-explicit-any -- EventEmitter's fallback listener is intentionally untyped
|
|
54
54
|
once(event, listener) {
|
|
55
55
|
return super.once(event, listener);
|
|
56
56
|
}
|
|
57
|
-
//
|
|
57
|
+
// oxlint-disable-next-line typescript/no-explicit-any -- EventEmitter's fallback listener is intentionally untyped
|
|
58
58
|
off(event, listener) {
|
|
59
59
|
return super.off(event, listener);
|
|
60
60
|
}
|
|
@@ -11,6 +11,7 @@ export interface ChildUnwindRequest {
|
|
|
11
11
|
emitter: WorkflowEmitter | null;
|
|
12
12
|
workflows?: Map<string, Workflow>;
|
|
13
13
|
retryFailed?: boolean;
|
|
14
|
+
assertActive: () => void;
|
|
14
15
|
}
|
|
15
16
|
export type ChildUnwind = (request: ChildUnwindRequest) => Promise<'ran' | LostCompensationClaim>;
|
|
16
17
|
export interface UnwindChildRequest {
|
|
@@ -20,6 +21,7 @@ export interface UnwindChildRequest {
|
|
|
20
21
|
workflows?: Map<string, Workflow>;
|
|
21
22
|
runChild: ChildUnwind;
|
|
22
23
|
retryFailed?: boolean;
|
|
24
|
+
assertActive: () => void;
|
|
23
25
|
}
|
|
24
26
|
/** Run the child workflow's own unwind and propagate every uncertain outcome. */
|
|
25
27
|
export declare function unwindChild(request: UnwindChildRequest): Promise<void>;
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
import { isLive } from './admission';
|
|
3
3
|
/** Run the child workflow's own unwind and propagate every uncertain outcome. */
|
|
4
4
|
export async function unwindChild(request) {
|
|
5
|
-
const { record, store, emitter, workflows, runChild, retryFailed } = request;
|
|
5
|
+
const { record, store, emitter, workflows, runChild, retryFailed, assertActive } = request;
|
|
6
|
+
assertActive();
|
|
6
7
|
const childId = record.childExecutionId;
|
|
7
8
|
if (!childId)
|
|
8
9
|
throw new Error('sub-workflow record carries no child execution id');
|
|
@@ -29,6 +30,7 @@ export async function unwindChild(request) {
|
|
|
29
30
|
emitter,
|
|
30
31
|
workflows,
|
|
31
32
|
retryFailed,
|
|
33
|
+
assertActive,
|
|
32
34
|
});
|
|
33
35
|
if (outcome !== 'ran') {
|
|
34
36
|
throw new Error(`child "${child.workflowName}" (${childId}) is being rolled back by another driver; ` +
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
/** One checkpointed compensation pass. */
|
|
2
2
|
import { compensationContext, settle } from './compensationSupport';
|
|
3
3
|
import { unwindChild } from './compensationChild';
|
|
4
|
+
import { isWorkflowExecutionClosed } from './executionFence';
|
|
4
5
|
import { describeError } from './identity';
|
|
5
6
|
import { buildContext, findStepDef, runWithTimeout } from './runner';
|
|
6
7
|
import { decideUnwindAction } from './unwindPlan';
|
|
7
8
|
export async function unwind(pass, runChild) {
|
|
8
|
-
const { exec, wf, store, emitter, eligible, workflows, retryFailed } = pass;
|
|
9
|
+
const { exec, wf, store, emitter, eligible, workflows, retryFailed, assertActive } = pass;
|
|
9
10
|
const baseCtx = buildContext(exec);
|
|
10
11
|
let haltedAt = null;
|
|
11
12
|
let writeFailure;
|
|
13
|
+
assertActive();
|
|
12
14
|
exec.state = 'compensating';
|
|
13
15
|
try {
|
|
14
16
|
store.update(exec);
|
|
@@ -20,8 +22,10 @@ export async function unwind(pass, runChild) {
|
|
|
20
22
|
}
|
|
21
23
|
if (writeFailure === undefined) {
|
|
22
24
|
emitter?.emitWorkflow('workflow:compensating', exec.id, exec.workflowName, 'compensating');
|
|
25
|
+
assertActive();
|
|
23
26
|
}
|
|
24
27
|
for (const [name, record] of eligible) {
|
|
28
|
+
assertActive();
|
|
25
29
|
if (writeFailure !== undefined)
|
|
26
30
|
break;
|
|
27
31
|
const action = decideUnwindAction(wf, name, record, haltedAt !== null, retryFailed);
|
|
@@ -39,12 +43,22 @@ export async function unwind(pass, runChild) {
|
|
|
39
43
|
emitter?.emitStep('compensation:failed', exec.id, exec.workflowName, name, {
|
|
40
44
|
error: 'step no longer declared',
|
|
41
45
|
});
|
|
46
|
+
assertActive();
|
|
42
47
|
continue;
|
|
43
48
|
}
|
|
44
49
|
emitter?.emitStep('compensation:started', exec.id, exec.workflowName, name);
|
|
50
|
+
assertActive();
|
|
45
51
|
try {
|
|
46
52
|
if (action.kind === 'unwind-child') {
|
|
47
|
-
await unwindChild({
|
|
53
|
+
await unwindChild({
|
|
54
|
+
record,
|
|
55
|
+
store,
|
|
56
|
+
emitter,
|
|
57
|
+
workflows,
|
|
58
|
+
runChild,
|
|
59
|
+
retryFailed,
|
|
60
|
+
assertActive,
|
|
61
|
+
});
|
|
48
62
|
}
|
|
49
63
|
else {
|
|
50
64
|
const def = findStepDef(wf, name);
|
|
@@ -59,6 +73,8 @@ export async function unwind(pass, runChild) {
|
|
|
59
73
|
emitter?.emitStep('compensation:completed', exec.id, exec.workflowName, name);
|
|
60
74
|
}
|
|
61
75
|
catch (error) {
|
|
76
|
+
if (isWorkflowExecutionClosed(error))
|
|
77
|
+
throw error;
|
|
62
78
|
const message = describeError(error);
|
|
63
79
|
settle(record, 'compensation-failed', message);
|
|
64
80
|
emitter?.emitStep('compensation:failed', exec.id, exec.workflowName, name, {
|
|
@@ -25,9 +25,10 @@ export type UnwindOutcome = 'ran' | LostCompensationClaim;
|
|
|
25
25
|
/** Run compensation handlers in reverse start order for every eligible step. */
|
|
26
26
|
export declare function runCompensation(exec: Execution, wf: Workflow, store: WorkflowStore, emitter: WorkflowEmitter | null, workflows?: Map<string, Workflow>, opts?: {
|
|
27
27
|
retryFailed?: boolean;
|
|
28
|
+
assertActive?: () => void;
|
|
28
29
|
}): Promise<UnwindOutcome>;
|
|
29
30
|
/**
|
|
30
31
|
* Give up on a parked unwind and record an explicit skipped outcome for every
|
|
31
32
|
* remaining eligible step.
|
|
32
33
|
*/
|
|
33
|
-
export declare function abandonCompensation(exec: Execution, wf: Workflow, store: WorkflowStore, emitter: WorkflowEmitter | null): void;
|
|
34
|
+
export declare function abandonCompensation(exec: Execution, wf: Workflow, store: WorkflowStore, emitter: WorkflowEmitter | null, assertActive?: () => void): void;
|
|
@@ -9,6 +9,7 @@ import { unwind } from './compensationPass';
|
|
|
9
9
|
import { AbandonedCompensationError } from './compensationChild';
|
|
10
10
|
import { acquireCompensationClaim } from './compensationClaim';
|
|
11
11
|
import { settle, unwindSet } from './compensationSupport';
|
|
12
|
+
import { assertWorkflowActive } from './executionFence';
|
|
12
13
|
import { owesOutcome } from './unwindPlan';
|
|
13
14
|
export { AbandonedCompensationError, CommittedChildError } from './compensationChild';
|
|
14
15
|
/** Sentinel thrown when an execution deliberately parks for a signal. */
|
|
@@ -20,8 +21,10 @@ export class WaitForSignalError extends Error {
|
|
|
20
21
|
}
|
|
21
22
|
}
|
|
22
23
|
/** Run compensation handlers in reverse start order for every eligible step. */
|
|
23
|
-
//
|
|
24
|
+
// oxlint-disable-next-line max-params -- registry and operator retry are independent inputs
|
|
24
25
|
export async function runCompensation(exec, wf, store, emitter, workflows, opts = {}) {
|
|
26
|
+
const assertActive = opts.assertActive ?? assertWorkflowActive;
|
|
27
|
+
assertActive();
|
|
25
28
|
// `failed` + `stuck` is the durable terminal form written by an explicit
|
|
26
29
|
// abandon. No caller, including an ancestor retry, may reopen that decision.
|
|
27
30
|
if (exec.state === 'failed' && exec.rollbackStatus === 'stuck') {
|
|
@@ -29,17 +32,19 @@ export async function runCompensation(exec, wf, store, emitter, workflows, opts
|
|
|
29
32
|
}
|
|
30
33
|
const eligible = unwindSet(exec, wf);
|
|
31
34
|
if (eligible.length === 0) {
|
|
35
|
+
assertActive();
|
|
32
36
|
exec.rollbackStatus = 'not-applicable';
|
|
33
37
|
if (exec.state !== 'failed' && exec.state !== 'completed')
|
|
34
38
|
exec.state = 'failed';
|
|
35
39
|
store.update(exec);
|
|
36
40
|
return 'ran';
|
|
37
41
|
}
|
|
42
|
+
assertActive();
|
|
38
43
|
const claim = acquireCompensationClaim(exec.id, store);
|
|
39
44
|
if (claim.kind === 'claim-lost')
|
|
40
45
|
return claim;
|
|
41
46
|
try {
|
|
42
|
-
await unwind({ exec, wf, store, emitter, eligible, workflows, ...opts }, ({ exec, workflow, store, emitter, workflows, retryFailed }) => runCompensation(exec, workflow, store, emitter, workflows, { retryFailed }));
|
|
47
|
+
await unwind({ exec, wf, store, emitter, eligible, workflows, ...opts, assertActive }, ({ exec, workflow, store, emitter, workflows, retryFailed, assertActive }) => runCompensation(exec, workflow, store, emitter, workflows, { retryFailed, assertActive }));
|
|
43
48
|
}
|
|
44
49
|
finally {
|
|
45
50
|
claim.release();
|
|
@@ -50,8 +55,9 @@ export async function runCompensation(exec, wf, store, emitter, workflows, opts
|
|
|
50
55
|
* Give up on a parked unwind and record an explicit skipped outcome for every
|
|
51
56
|
* remaining eligible step.
|
|
52
57
|
*/
|
|
53
|
-
export function abandonCompensation(exec, wf, store, emitter) {
|
|
58
|
+
export function abandonCompensation(exec, wf, store, emitter, assertActive = assertWorkflowActive) {
|
|
54
59
|
for (const [name, record] of unwindSet(exec, wf)) {
|
|
60
|
+
assertActive();
|
|
55
61
|
if (record.compensation)
|
|
56
62
|
continue;
|
|
57
63
|
if (!owesOutcome(wf, name, record))
|
|
@@ -59,7 +65,9 @@ export function abandonCompensation(exec, wf, store, emitter) {
|
|
|
59
65
|
const reason = 'unwind abandoned by operator';
|
|
60
66
|
settle(record, 'compensation-skipped', reason);
|
|
61
67
|
emitter?.emitStep('compensation:skipped', exec.id, exec.workflowName, name, { error: reason });
|
|
68
|
+
assertActive();
|
|
62
69
|
}
|
|
70
|
+
assertActive();
|
|
63
71
|
exec.state = 'failed';
|
|
64
72
|
exec.rollbackStatus = 'stuck';
|
|
65
73
|
store.update(exec);
|
|
@@ -136,7 +136,7 @@ export class Engine {
|
|
|
136
136
|
// Before the worker: a waitFor timer that fires during shutdown enqueues a step
|
|
137
137
|
// job, and a queue closing underneath it turns an orderly shutdown into a rejected
|
|
138
138
|
// add. Releasing the timers first makes the order irrelevant.
|
|
139
|
-
this.executor.close();
|
|
139
|
+
this.executor.close(force);
|
|
140
140
|
await this.worker.close(force);
|
|
141
141
|
this.queue.close();
|
|
142
142
|
this.store.close();
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Lifecycle fence shared by every asynchronous workflow execution path. */
|
|
2
|
+
/** Internal control-flow signal used to abandon work owned by a closed Engine. */
|
|
3
|
+
export declare class WorkflowExecutionClosedError extends Error {
|
|
4
|
+
constructor();
|
|
5
|
+
}
|
|
6
|
+
export declare function isWorkflowExecutionClosed(error: unknown): boolean;
|
|
7
|
+
/** A graceful close leaves this active; only close(true) aborts in-flight control flow. */
|
|
8
|
+
export declare class WorkflowExecutionFence {
|
|
9
|
+
private readonly controller;
|
|
10
|
+
readonly assertActive: () => void;
|
|
11
|
+
isActive(): boolean;
|
|
12
|
+
close(force: boolean): void;
|
|
13
|
+
}
|
|
14
|
+
/** Default for isolated runner tests that do not own an Engine lifecycle. */
|
|
15
|
+
export declare const assertWorkflowActive: () => void;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** Lifecycle fence shared by every asynchronous workflow execution path. */
|
|
2
|
+
/** Internal control-flow signal used to abandon work owned by a closed Engine. */
|
|
3
|
+
export class WorkflowExecutionClosedError extends Error {
|
|
4
|
+
constructor() {
|
|
5
|
+
super('Workflow execution belongs to a force-closed Engine');
|
|
6
|
+
this.name = 'WorkflowExecutionClosedError';
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export function isWorkflowExecutionClosed(error) {
|
|
10
|
+
return (error instanceof WorkflowExecutionClosedError ||
|
|
11
|
+
(error instanceof AggregateError && error.errors.some(isWorkflowExecutionClosed)));
|
|
12
|
+
}
|
|
13
|
+
/** A graceful close leaves this active; only close(true) aborts in-flight control flow. */
|
|
14
|
+
export class WorkflowExecutionFence {
|
|
15
|
+
controller = new AbortController();
|
|
16
|
+
assertActive = () => {
|
|
17
|
+
if (this.controller.signal.aborted)
|
|
18
|
+
throw new WorkflowExecutionClosedError();
|
|
19
|
+
};
|
|
20
|
+
isActive() {
|
|
21
|
+
return !this.controller.signal.aborted;
|
|
22
|
+
}
|
|
23
|
+
close(force) {
|
|
24
|
+
if (force)
|
|
25
|
+
this.controller.abort();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/** Default for isolated runner tests that do not own an Engine lifecycle. */
|
|
29
|
+
export const assertWorkflowActive = () => undefined;
|
|
@@ -10,13 +10,14 @@ export declare class WorkflowExecutor {
|
|
|
10
10
|
private readonly emitter;
|
|
11
11
|
private readonly workflows;
|
|
12
12
|
private readonly timeoutTimers;
|
|
13
|
+
private readonly fence;
|
|
13
14
|
/**
|
|
14
15
|
* Release every armed waitFor timer. The engine owns the executor's lifetime, so
|
|
15
16
|
* `Engine.close()` must call this: an armed timer would otherwise fire into a
|
|
16
17
|
* closing queue, and a caller that keeps the process alive after closing one engine
|
|
17
18
|
* has no other handle on them.
|
|
18
19
|
*/
|
|
19
|
-
close(): void;
|
|
20
|
+
close(force?: boolean): void;
|
|
20
21
|
private readonly updateFn;
|
|
21
22
|
constructor(store: WorkflowStore, queue: Queue, emitter?: WorkflowEmitter | null);
|
|
22
23
|
register(workflow: Workflow): void;
|
|
@@ -24,16 +25,9 @@ export declare class WorkflowExecutor {
|
|
|
24
25
|
/**
|
|
25
26
|
* Nodes this process is currently executing, keyed `<execution>:<nodeIndex>`.
|
|
26
27
|
*
|
|
27
|
-
* The cursor
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* `running` execution and is documented as callable on a live engine. Without this
|
|
31
|
-
* claim the node runs twice and each copy advances the run independently, doubling
|
|
32
|
-
* every side effect after it while the run still ends `completed`.
|
|
33
|
-
*
|
|
34
|
-
* A claim, not a queue-level dedup: a deterministic `jobId` was tried and could
|
|
35
|
-
* swallow a LEGITIMATE later re-enqueue of the same node, wedging the run forever.
|
|
36
|
-
* This drops only a duplicate that overlaps in time.
|
|
28
|
+
* The cursor rejects stale jobs but not two overlapping deliveries for the current
|
|
29
|
+
* node. This process-local claim drops that overlap. Queue-level dedup is unsuitable:
|
|
30
|
+
* a retained ID can swallow a legitimate recovery enqueue and wedge the run.
|
|
37
31
|
*/
|
|
38
32
|
private readonly nodesInFlight;
|
|
39
33
|
processStep(data: StepJobData): Promise<unknown>;
|