taskito 0.16.1__tar.gz → 0.16.2__tar.gz
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.
- {taskito-0.16.1 → taskito-0.16.2}/Cargo.lock +21 -21
- {taskito-0.16.1 → taskito-0.16.2}/PKG-INFO +1 -1
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/Cargo.toml +5 -1
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/scheduler/poller.rs +16 -9
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/diesel_common/jobs.rs +25 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/mod.rs +6 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/redis_backend/dead_letter.rs +25 -9
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/redis_backend/jobs/dequeue.rs +57 -12
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/redis_backend/jobs/helpers.rs +104 -34
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/redis_backend/jobs/state.rs +74 -15
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/sqlite/tests.rs +33 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/traits.rs +5 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/tests/rust/storage_tests.rs +220 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-python/Cargo.toml +1 -1
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-workflows/Cargo.toml +1 -1
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/__init__.py +1 -1
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/dashboard/handlers/settings.py +6 -2
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/notes.py +14 -1
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/result.py +5 -1
- {taskito-0.16.1 → taskito-0.16.2}/pyproject.toml +1 -1
- {taskito-0.16.1 → taskito-0.16.2}/Cargo.toml +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/LICENSE +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/README.md +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/error.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/job.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/lib.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/periodic.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/resilience/circuit_breaker.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/resilience/dlq.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/resilience/mod.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/resilience/rate_limiter.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/resilience/retry.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/scheduler/maintenance.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/scheduler/mod.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/scheduler/result_handler.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/scheduler/wake.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/diesel_common/archival.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/diesel_common/dead_letter.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/diesel_common/locks.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/diesel_common/logs.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/diesel_common/metrics.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/diesel_common/migrations.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/diesel_common/mod.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/diesel_common/workers.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/models.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/notify.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/postgres/archival.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/postgres/circuit_breakers.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/postgres/dashboard_settings.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/postgres/dead_letter.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/postgres/jobs.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/postgres/listener.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/postgres/locks.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/postgres/logs.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/postgres/metrics.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/postgres/mod.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/postgres/periodic.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/postgres/queue_state.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/postgres/rate_limits.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/postgres/trait_impl.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/postgres/workers.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/redis_backend/archival.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/redis_backend/circuit_breakers.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/redis_backend/dashboard_settings.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/redis_backend/jobs/enqueue.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/redis_backend/jobs/errors.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/redis_backend/jobs/maintenance.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/redis_backend/jobs/mod.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/redis_backend/jobs/query.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/redis_backend/listener.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/redis_backend/locks.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/redis_backend/logs.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/redis_backend/metrics.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/redis_backend/mod.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/redis_backend/periodic.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/redis_backend/queue_state.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/redis_backend/rate_limits.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/redis_backend/trait_impl.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/redis_backend/workers.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/schema.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/sqlite/archival.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/sqlite/circuit_breakers.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/sqlite/dashboard_settings.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/sqlite/dead_letter.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/sqlite/jobs.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/sqlite/locks.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/sqlite/logs.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/sqlite/metrics.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/sqlite/mod.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/sqlite/periodic.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/sqlite/queue_state.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/sqlite/rate_limits.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/sqlite/trait_impl.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/sqlite/workers.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/worker.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/tests/rust.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-python/src/async_worker.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-python/src/lib.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-python/src/prefork/child.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-python/src/prefork/dispatch.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-python/src/prefork/mod.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-python/src/prefork/protocol.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-python/src/prefork/slot.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-python/src/prefork/watchdog.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-python/src/py_config.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-python/src/py_job.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-python/src/py_queue/inspection.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-python/src/py_queue/mod.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-python/src/py_queue/worker.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-python/src/py_queue/workflow_ops/fan_out.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-python/src/py_queue/workflow_ops/gates.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-python/src/py_queue/workflow_ops/lifecycle.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-python/src/py_queue/workflow_ops/mod.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-python/src/py_queue/workflow_ops/nodes.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-python/src/py_queue/workflow_ops/queries.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-python/src/py_queue/workflow_ops/saga.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-python/src/py_queue/workflow_ops/test_helpers.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-python/src/py_worker.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-python/src/py_workflow/mod.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-workflows/src/common.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-workflows/src/definition.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-workflows/src/diesel_common.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-workflows/src/error.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-workflows/src/lib.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-workflows/src/node.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-workflows/src/postgres_store.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-workflows/src/redis_store.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-workflows/src/run.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-workflows/src/sqlite_store.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-workflows/src/state.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-workflows/src/storage.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-workflows/src/tests.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-workflows/src/topology.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/crates/taskito-workflows/tests/storage_contract.rs +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/_active_context.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/_taskito.pyi +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/app.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/async_support/__init__.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/async_support/canvas.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/async_support/context.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/async_support/executor.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/async_support/helpers.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/async_support/locks.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/async_support/mixins.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/async_support/result.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/autoscale/__init__.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/autoscale/config.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/autoscale/controller.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/autoscale/process_manager.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/batching/__init__.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/batching/accumulator.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/batching/config.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/batching/item_result.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/batching/result.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/canvas.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/cli.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/context.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/contrib/__init__.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/contrib/django/__init__.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/contrib/django/admin.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/contrib/django/apps.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/contrib/django/management/__init__.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/contrib/django/management/commands/__init__.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/contrib/django/management/commands/taskito_dashboard.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/contrib/django/management/commands/taskito_info.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/contrib/django/management/commands/taskito_worker.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/contrib/django/settings.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/contrib/fastapi.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/contrib/flask.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/contrib/otel.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/contrib/prometheus.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/contrib/sentry.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/dashboard/__init__.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/dashboard/_testing.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/dashboard/auth.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/dashboard/delivery_store.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/dashboard/errors.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/dashboard/handlers/__init__.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/dashboard/handlers/_qs.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/dashboard/handlers/auth.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/dashboard/handlers/dead_letters.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/dashboard/handlers/jobs.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/dashboard/handlers/logs.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/dashboard/handlers/metrics.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/dashboard/handlers/middleware.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/dashboard/handlers/oauth.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/dashboard/handlers/overrides.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/dashboard/handlers/queues.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/dashboard/handlers/scaler.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/dashboard/handlers/webhook_deliveries.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/dashboard/handlers/webhooks.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/dashboard/handlers/workflows.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/dashboard/middleware_store.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/dashboard/oauth/__init__.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/dashboard/oauth/config.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/dashboard/oauth/flow.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/dashboard/oauth/identity.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/dashboard/oauth/pkce.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/dashboard/oauth/providers.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/dashboard/oauth/state_store.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/dashboard/overrides_store.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/dashboard/request_context.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/dashboard/routes.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/dashboard/server.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/dashboard/static.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/dashboard/url_safety.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/dashboard/webhook_store.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/events.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/exceptions.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/health.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/inject.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/interception/__init__.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/interception/built_in.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/interception/converters.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/interception/errors.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/interception/interceptor.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/interception/metrics.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/interception/reconstruct.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/interception/registry.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/interception/strategy.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/interception/walker.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/locks.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/log_config.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/mesh.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/middleware.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/mixins/__init__.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/mixins/_shared.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/mixins/decorators.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/mixins/events.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/mixins/inspection.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/mixins/lifecycle.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/mixins/locks.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/mixins/middleware_admin.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/mixins/operations.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/mixins/overrides.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/mixins/predicates.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/mixins/resources.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/mixins/runtime_config.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/mixins/settings.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/predicates/__init__.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/predicates/context.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/predicates/core.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/predicates/evaluate.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/predicates/metrics.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/predicates/outcomes.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/predicates/parser.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/predicates/providers.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/predicates/recipes/__init__.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/predicates/recipes/attributes.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/predicates/recipes/config.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/predicates/recipes/system.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/predicates/recipes/time.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/predicates/registry.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/prefork/__init__.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/prefork/__main__.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/prefork/child.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/proxies/__init__.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/proxies/built_in.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/proxies/handler.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/proxies/handlers/__init__.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/proxies/handlers/boto3_client.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/proxies/handlers/file.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/proxies/handlers/gcs_client.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/proxies/handlers/httpx_client.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/proxies/handlers/logger.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/proxies/handlers/requests_session.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/proxies/metrics.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/proxies/no_proxy.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/proxies/reconstruct.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/proxies/registry.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/proxies/schema.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/proxies/signing.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/py.typed +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/resources/__init__.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/resources/definition.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/resources/frozen.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/resources/graph.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/resources/health.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/resources/pool.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/resources/runtime.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/resources/thread_local.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/resources/toml_config.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/scaler.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/serializers.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/static/dashboard/assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/static/dashboard/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/static/dashboard/assets/ibm-plex-mono-latin-500-normal-CB9ihrfo.woff +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/static/dashboard/assets/ibm-plex-mono-latin-500-normal-DSY6xOcd.woff2 +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/static/dashboard/assets/ibm-plex-mono-latin-600-normal-BgSNZQsw.woff2 +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/static/dashboard/assets/ibm-plex-mono-latin-600-normal-DWFSQ4vo.woff +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/static/dashboard/assets/ibm-plex-sans-latin-400-normal-CDDApCn2.woff2 +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/static/dashboard/assets/ibm-plex-sans-latin-400-normal-CYLoc0-x.woff +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/static/dashboard/assets/ibm-plex-sans-latin-500-normal-6ng42L7E.woff2 +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/static/dashboard/assets/ibm-plex-sans-latin-500-normal-BgVn5rGT.woff +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/static/dashboard/assets/ibm-plex-sans-latin-600-normal-Cu4Hd6ag.woff +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/static/dashboard/assets/ibm-plex-sans-latin-600-normal-CuJfVYMP.woff2 +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/static/dashboard/assets/ibm-plex-serif-latin-500-normal-C3_OdgN3.woff +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/static/dashboard/assets/ibm-plex-serif-latin-500-normal-REKAfBVG.woff2 +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/static/dashboard/assets/ibm-plex-serif-latin-600-normal-D3rpGdkS.woff +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/static/dashboard/assets/ibm-plex-serif-latin-600-normal-DAxitmSu.woff2 +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/static/dashboard/assets/index-W-qtINsk.js +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/static/dashboard/assets/index-XTjpQV4Y.css +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/static/dashboard/assets/logs.lazy-BRzWGIVq.js +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/static/dashboard/assets/metrics.lazy-7u0OCPof.js +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/static/dashboard/index.html +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/task.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/testing.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/webhooks.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/workflows/__init__.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/workflows/analysis.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/workflows/builder.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/workflows/context.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/workflows/fan_out.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/workflows/incremental.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/workflows/mixins.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/workflows/run.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/workflows/saga/__init__.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/workflows/saga/context.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/workflows/saga/orchestrator.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/workflows/tracker/__init__.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/workflows/tracker/dag.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/workflows/tracker/event_routing.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/workflows/tracker/fan_out.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/workflows/tracker/finalization.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/workflows/tracker/gates.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/workflows/tracker/sub_workflows.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/workflows/tracker/tracker.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/workflows/tracker/types.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/workflows/types.py +0 -0
- {taskito-0.16.1 → taskito-0.16.2}/py_src/taskito/workflows/visualization.py +0 -0
|
@@ -112,9 +112,9 @@ checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
|
|
|
112
112
|
|
|
113
113
|
[[package]]
|
|
114
114
|
name = "cc"
|
|
115
|
-
version = "1.2.
|
|
115
|
+
version = "1.2.64"
|
|
116
116
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
117
|
-
checksum = "
|
|
117
|
+
checksum = "dad887fd958be91b5098c0248def011f4523ab786cd411be668777e55063501f"
|
|
118
118
|
dependencies = [
|
|
119
119
|
"find-msvc-tools",
|
|
120
120
|
"shlex",
|
|
@@ -676,9 +676,9 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
|
|
676
676
|
|
|
677
677
|
[[package]]
|
|
678
678
|
name = "js-sys"
|
|
679
|
-
version = "0.3.
|
|
679
|
+
version = "0.3.102"
|
|
680
680
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
681
|
-
checksum = "
|
|
681
|
+
checksum = "03d04c30968dffe80775bd4d7fb676131cd04a1fb46d2686dbffbaec2d9dfd31"
|
|
682
682
|
dependencies = [
|
|
683
683
|
"cfg-if",
|
|
684
684
|
"futures-util",
|
|
@@ -821,9 +821,9 @@ dependencies = [
|
|
|
821
821
|
|
|
822
822
|
[[package]]
|
|
823
823
|
name = "openssl-sys"
|
|
824
|
-
version = "0.9.
|
|
824
|
+
version = "0.9.117"
|
|
825
825
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
826
|
-
checksum = "
|
|
826
|
+
checksum = "b47e7e6bb2c38cd930d25a23b40fa52e068c10e85f3e03a7f5ba5aaca5713695"
|
|
827
827
|
dependencies = [
|
|
828
828
|
"cc",
|
|
829
829
|
"libc",
|
|
@@ -1403,7 +1403,7 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
|
|
|
1403
1403
|
|
|
1404
1404
|
[[package]]
|
|
1405
1405
|
name = "taskito-async"
|
|
1406
|
-
version = "0.16.
|
|
1406
|
+
version = "0.16.2"
|
|
1407
1407
|
dependencies = [
|
|
1408
1408
|
"async-trait",
|
|
1409
1409
|
"crossbeam-channel",
|
|
@@ -1415,7 +1415,7 @@ dependencies = [
|
|
|
1415
1415
|
|
|
1416
1416
|
[[package]]
|
|
1417
1417
|
name = "taskito-core"
|
|
1418
|
-
version = "0.16.
|
|
1418
|
+
version = "0.16.2"
|
|
1419
1419
|
dependencies = [
|
|
1420
1420
|
"async-trait",
|
|
1421
1421
|
"chrono",
|
|
@@ -1439,7 +1439,7 @@ dependencies = [
|
|
|
1439
1439
|
|
|
1440
1440
|
[[package]]
|
|
1441
1441
|
name = "taskito-mesh"
|
|
1442
|
-
version = "0.16.
|
|
1442
|
+
version = "0.16.2"
|
|
1443
1443
|
dependencies = [
|
|
1444
1444
|
"base64",
|
|
1445
1445
|
"bincode",
|
|
@@ -1454,7 +1454,7 @@ dependencies = [
|
|
|
1454
1454
|
|
|
1455
1455
|
[[package]]
|
|
1456
1456
|
name = "taskito-python"
|
|
1457
|
-
version = "0.16.
|
|
1457
|
+
version = "0.16.2"
|
|
1458
1458
|
dependencies = [
|
|
1459
1459
|
"async-trait",
|
|
1460
1460
|
"base64",
|
|
@@ -1475,7 +1475,7 @@ dependencies = [
|
|
|
1475
1475
|
|
|
1476
1476
|
[[package]]
|
|
1477
1477
|
name = "taskito-workflows"
|
|
1478
|
-
version = "0.16.
|
|
1478
|
+
version = "0.16.2"
|
|
1479
1479
|
dependencies = [
|
|
1480
1480
|
"dagron-core",
|
|
1481
1481
|
"diesel",
|
|
@@ -1656,9 +1656,9 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
|
|
1656
1656
|
|
|
1657
1657
|
[[package]]
|
|
1658
1658
|
name = "wasip2"
|
|
1659
|
-
version = "1.0.
|
|
1659
|
+
version = "1.0.4+wasi-0.2.12"
|
|
1660
1660
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1661
|
-
checksum = "
|
|
1661
|
+
checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487"
|
|
1662
1662
|
dependencies = [
|
|
1663
1663
|
"wit-bindgen 0.57.1",
|
|
1664
1664
|
]
|
|
@@ -1674,9 +1674,9 @@ dependencies = [
|
|
|
1674
1674
|
|
|
1675
1675
|
[[package]]
|
|
1676
1676
|
name = "wasm-bindgen"
|
|
1677
|
-
version = "0.2.
|
|
1677
|
+
version = "0.2.125"
|
|
1678
1678
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1679
|
-
checksum = "
|
|
1679
|
+
checksum = "8ddb3f79143bced6de84270411622a2699cee572fc0875aeaf1e7867cf9fca1a"
|
|
1680
1680
|
dependencies = [
|
|
1681
1681
|
"cfg-if",
|
|
1682
1682
|
"once_cell",
|
|
@@ -1687,9 +1687,9 @@ dependencies = [
|
|
|
1687
1687
|
|
|
1688
1688
|
[[package]]
|
|
1689
1689
|
name = "wasm-bindgen-macro"
|
|
1690
|
-
version = "0.2.
|
|
1690
|
+
version = "0.2.125"
|
|
1691
1691
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1692
|
-
checksum = "
|
|
1692
|
+
checksum = "4e21a184b13fb19e157296e2c46056aec9092264fab83e4ba59e68c61b323c3d"
|
|
1693
1693
|
dependencies = [
|
|
1694
1694
|
"quote",
|
|
1695
1695
|
"wasm-bindgen-macro-support",
|
|
@@ -1697,9 +1697,9 @@ dependencies = [
|
|
|
1697
1697
|
|
|
1698
1698
|
[[package]]
|
|
1699
1699
|
name = "wasm-bindgen-macro-support"
|
|
1700
|
-
version = "0.2.
|
|
1700
|
+
version = "0.2.125"
|
|
1701
1701
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1702
|
-
checksum = "
|
|
1702
|
+
checksum = "fecefd9c35bd935a20fc3fc344b5f29138961e4f47fb03297d88f2587afb5ebd"
|
|
1703
1703
|
dependencies = [
|
|
1704
1704
|
"bumpalo",
|
|
1705
1705
|
"proc-macro2",
|
|
@@ -1710,9 +1710,9 @@ dependencies = [
|
|
|
1710
1710
|
|
|
1711
1711
|
[[package]]
|
|
1712
1712
|
name = "wasm-bindgen-shared"
|
|
1713
|
-
version = "0.2.
|
|
1713
|
+
version = "0.2.125"
|
|
1714
1714
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1715
|
-
checksum = "
|
|
1715
|
+
checksum = "23939e44bb9a5d7576fa2b563dc2e136628f1224e88a8deed09e04858b77871f"
|
|
1716
1716
|
dependencies = [
|
|
1717
1717
|
"unicode-ident",
|
|
1718
1718
|
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "taskito-core"
|
|
3
|
-
version = "0.16.
|
|
3
|
+
version = "0.16.2"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
|
|
6
6
|
[features]
|
|
@@ -32,3 +32,7 @@ redis = { workspace = true, optional = true }
|
|
|
32
32
|
|
|
33
33
|
[dev-dependencies]
|
|
34
34
|
tempfile = "3"
|
|
35
|
+
# Raw connection access in the Redis contract tests, to set up race-window
|
|
36
|
+
# state and assert on internal index keys. Only used by `#[cfg(feature = "redis")]`
|
|
37
|
+
# tests; harmless when the feature is off.
|
|
38
|
+
redis = { workspace = true }
|
|
@@ -127,7 +127,7 @@ impl Scheduler {
|
|
|
127
127
|
// If we exceed the cap, roll back: clear the claim row and reset
|
|
128
128
|
// status to `Pending` so the job can be dispatched again later.
|
|
129
129
|
if !self.check_post_claim_concurrency(&job)? {
|
|
130
|
-
self.
|
|
130
|
+
self.rollback_claim_and_reschedule(&job.id, now + CONCURRENCY_RETRY_DELAY_MS)?;
|
|
131
131
|
return Ok(false);
|
|
132
132
|
}
|
|
133
133
|
|
|
@@ -140,14 +140,20 @@ impl Scheduler {
|
|
|
140
140
|
Ok(()) => Ok(true),
|
|
141
141
|
Err(TrySendError::Full(_)) => {
|
|
142
142
|
warn!("worker channel full; rescheduling job {job_id} (worker pool is behind)",);
|
|
143
|
-
self.
|
|
143
|
+
self.rollback_claim_and_reschedule(
|
|
144
|
+
&job_id,
|
|
145
|
+
now + CHANNEL_BACKPRESSURE_RETRY_DELAY_MS,
|
|
146
|
+
)?;
|
|
144
147
|
Ok(false)
|
|
145
148
|
}
|
|
146
149
|
Err(TrySendError::Closed(_)) => {
|
|
147
150
|
warn!(
|
|
148
151
|
"worker channel closed; rescheduling job {job_id} (worker pool shutting down)",
|
|
149
152
|
);
|
|
150
|
-
self.
|
|
153
|
+
self.rollback_claim_and_reschedule(
|
|
154
|
+
&job_id,
|
|
155
|
+
now + CHANNEL_BACKPRESSURE_RETRY_DELAY_MS,
|
|
156
|
+
)?;
|
|
151
157
|
Ok(false)
|
|
152
158
|
}
|
|
153
159
|
}
|
|
@@ -193,7 +199,7 @@ impl Scheduler {
|
|
|
193
199
|
let key = format!("queue:{}", job.queue);
|
|
194
200
|
if !self.rate_limiter.try_acquire(&key, rl_config)? {
|
|
195
201
|
self.storage
|
|
196
|
-
.
|
|
202
|
+
.reschedule(&job.id, now + RATE_LIMIT_RETRY_DELAY_MS)?;
|
|
197
203
|
return Ok(false);
|
|
198
204
|
}
|
|
199
205
|
}
|
|
@@ -202,14 +208,14 @@ impl Scheduler {
|
|
|
202
208
|
if let Some(config) = self.task_configs.get(&job.task_name) {
|
|
203
209
|
if config.circuit_breaker.is_some() && !self.circuit_breaker.allow(&job.task_name)? {
|
|
204
210
|
self.storage
|
|
205
|
-
.
|
|
211
|
+
.reschedule(&job.id, now + CIRCUIT_BREAKER_RETRY_DELAY_MS)?;
|
|
206
212
|
return Ok(false);
|
|
207
213
|
}
|
|
208
214
|
|
|
209
215
|
if let Some(ref rl_config) = config.rate_limit {
|
|
210
216
|
if !self.rate_limiter.try_acquire(&job.task_name, rl_config)? {
|
|
211
217
|
self.storage
|
|
212
|
-
.
|
|
218
|
+
.reschedule(&job.id, now + RATE_LIMIT_RETRY_DELAY_MS)?;
|
|
213
219
|
return Ok(false);
|
|
214
220
|
}
|
|
215
221
|
}
|
|
@@ -265,11 +271,12 @@ impl Scheduler {
|
|
|
265
271
|
|
|
266
272
|
/// Reverse a successful `claim_execution` and reschedule the job. Used
|
|
267
273
|
/// when a post-claim gate rejects the job after the claim row has
|
|
268
|
-
/// already been written.
|
|
269
|
-
|
|
274
|
+
/// already been written. Uses `reschedule` (not `retry`) so a job that
|
|
275
|
+
/// never executed does not lose retry budget.
|
|
276
|
+
fn rollback_claim_and_reschedule(&self, job_id: &str, next_at: i64) -> Result<()> {
|
|
270
277
|
if let Err(e) = self.storage.complete_execution(job_id) {
|
|
271
278
|
warn!("failed to clear execution claim during rollback for job {job_id}: {e}");
|
|
272
279
|
}
|
|
273
|
-
self.storage.
|
|
280
|
+
self.storage.reschedule(job_id, next_at)
|
|
274
281
|
}
|
|
275
282
|
}
|
|
@@ -705,6 +705,31 @@ macro_rules! impl_diesel_job_ops {
|
|
|
705
705
|
Ok(())
|
|
706
706
|
}
|
|
707
707
|
|
|
708
|
+
/// Re-schedule a job back to `Pending` without touching
|
|
709
|
+
/// `retry_count`. Mirrors [`retry`](Self::retry) for soft-gate
|
|
710
|
+
/// reschedules (rate limit, circuit breaker, concurrency cap,
|
|
711
|
+
/// backpressure) where the job never executed, so its retry
|
|
712
|
+
/// budget must be preserved.
|
|
713
|
+
pub fn reschedule(&self, id: &str, next_scheduled_at: i64) -> Result<()> {
|
|
714
|
+
let mut conn = self.conn()?;
|
|
715
|
+
|
|
716
|
+
let affected = diesel::update(jobs::table)
|
|
717
|
+
.filter(jobs::id.eq(id))
|
|
718
|
+
.set((
|
|
719
|
+
jobs::status.eq(JobStatus::Pending as i32),
|
|
720
|
+
jobs::scheduled_at.eq(next_scheduled_at),
|
|
721
|
+
jobs::started_at.eq(None::<i64>),
|
|
722
|
+
jobs::completed_at.eq(None::<i64>),
|
|
723
|
+
jobs::error.eq(None::<String>),
|
|
724
|
+
))
|
|
725
|
+
.execute(&mut conn)?;
|
|
726
|
+
|
|
727
|
+
if affected == 0 {
|
|
728
|
+
return Err(QueueError::JobNotFound(id.to_string()));
|
|
729
|
+
}
|
|
730
|
+
Ok(())
|
|
731
|
+
}
|
|
732
|
+
|
|
708
733
|
/// Cancel a pending job and cascade-cancel its dependents. The
|
|
709
734
|
/// cancelled job moves from `jobs` into `archived_jobs`.
|
|
710
735
|
pub fn cancel_job(&self, id: &str) -> Result<bool> {
|
|
@@ -152,6 +152,9 @@ macro_rules! impl_storage {
|
|
|
152
152
|
fn retry(&self, id: &str, next_scheduled_at: i64) -> $crate::error::Result<()> {
|
|
153
153
|
self.retry(id, next_scheduled_at)
|
|
154
154
|
}
|
|
155
|
+
fn reschedule(&self, id: &str, next_scheduled_at: i64) -> $crate::error::Result<()> {
|
|
156
|
+
self.reschedule(id, next_scheduled_at)
|
|
157
|
+
}
|
|
155
158
|
fn cancel_job(&self, id: &str) -> $crate::error::Result<bool> {
|
|
156
159
|
self.cancel_job(id)
|
|
157
160
|
}
|
|
@@ -679,6 +682,9 @@ impl Storage for StorageBackend {
|
|
|
679
682
|
fn retry(&self, id: &str, next_scheduled_at: i64) -> Result<()> {
|
|
680
683
|
delegate!(self, retry, id, next_scheduled_at)
|
|
681
684
|
}
|
|
685
|
+
fn reschedule(&self, id: &str, next_scheduled_at: i64) -> Result<()> {
|
|
686
|
+
delegate!(self, reschedule, id, next_scheduled_at)
|
|
687
|
+
}
|
|
682
688
|
fn cancel_job(&self, id: &str) -> Result<bool> {
|
|
683
689
|
delegate!(self, cancel_job, id)
|
|
684
690
|
}
|
{taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/redis_backend/dead_letter.rs
RENAMED
|
@@ -89,22 +89,38 @@ impl RedisStorage {
|
|
|
89
89
|
let dlq_key = self.key(&["dlq", &dlq_id]);
|
|
90
90
|
let dlq_all = self.key(&["dlq", "all"]);
|
|
91
91
|
|
|
92
|
-
let pipe = &mut redis::pipe();
|
|
93
|
-
pipe.set(&dlq_key, &json);
|
|
94
|
-
pipe.zadd(&dlq_all, &dlq_id, now as f64);
|
|
95
|
-
pipe.query::<()>(&mut conn).map_err(map_err)?;
|
|
96
|
-
|
|
97
|
-
// Archive the now-Dead job out of the live indices.
|
|
98
92
|
let mut dead_job = job.clone();
|
|
99
93
|
let old_status = dead_job.status;
|
|
100
94
|
dead_job.status = JobStatus::Dead;
|
|
101
95
|
dead_job.error = Some(error.to_string());
|
|
102
96
|
dead_job.completed_at = Some(now);
|
|
103
|
-
|
|
97
|
+
let dead_json =
|
|
98
|
+
serde_json::to_string(&dead_job).map_err(|e| QueueError::Other(e.to_string()))?;
|
|
99
|
+
|
|
100
|
+
// Commit the DLQ entry and the live→archive move together, but only if the
|
|
101
|
+
// job is still live in its expected state. A racing complete/fail or the
|
|
102
|
+
// stale-job reaper may have archived it first; WATCH aborts the EXEC if
|
|
103
|
+
// `job:<id>` changes between the liveness check and the commit, so we never
|
|
104
|
+
// create a duplicate DLQ entry or overwrite a terminal archive.
|
|
105
|
+
let job_live_key = self.key(&["job", &job.id]);
|
|
106
|
+
let dead_lettered: bool =
|
|
107
|
+
redis::transaction(&mut conn, &[job_live_key.as_str()], |conn, pipe| {
|
|
108
|
+
if !conn.exists::<_, bool>(&job_live_key)? {
|
|
109
|
+
return Ok(Some(false));
|
|
110
|
+
}
|
|
111
|
+
pipe.set(&dlq_key, &json).ignore();
|
|
112
|
+
pipe.zadd(&dlq_all, &dlq_id, now as f64).ignore();
|
|
113
|
+
self.push_archive_ops(pipe, &dead_job, old_status, &dead_json);
|
|
114
|
+
Ok(pipe.query::<Option<()>>(conn)?.map(|()| true))
|
|
115
|
+
})
|
|
116
|
+
.map_err(map_err)?;
|
|
104
117
|
|
|
105
|
-
// Cascade
|
|
118
|
+
// Cascade-cancel dependents only if we actually dead-lettered the job
|
|
119
|
+
// (skipped when a racer had already archived it).
|
|
106
120
|
drop(conn);
|
|
107
|
-
|
|
121
|
+
if dead_lettered {
|
|
122
|
+
self.cascade_cancel(&job.id, "dependency failed")?;
|
|
123
|
+
}
|
|
108
124
|
|
|
109
125
|
Ok(())
|
|
110
126
|
}
|
{taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/redis_backend/jobs/dequeue.rs
RENAMED
|
@@ -6,7 +6,54 @@ use crate::error::{QueueError, Result};
|
|
|
6
6
|
use crate::job::{Job, JobStatus};
|
|
7
7
|
use crate::storage::redis_backend::{map_err, RedisStorage};
|
|
8
8
|
|
|
9
|
+
/// Lua: claim a candidate by flipping it Pending→Running, but only if it is
|
|
10
|
+
/// still a member of the pending status set (`jobs:status:0`). This is the
|
|
11
|
+
/// Redis equivalent of the Diesel `UPDATE ... WHERE status = Pending`
|
|
12
|
+
/// affected-row guard: a concurrent cancel/expire that already archived the
|
|
13
|
+
/// job has removed it from `jobs:status:0`, so the claim is refused (returns 0)
|
|
14
|
+
/// instead of resurrecting the job as a Running orphan. Redis runs the script
|
|
15
|
+
/// atomically, which also closes the double-claim window between schedulers.
|
|
16
|
+
///
|
|
17
|
+
/// KEYS: job_key, pending_status_set, running_status_set, pending_zset
|
|
18
|
+
/// ARGV: job_id, running_json
|
|
19
|
+
const CLAIM_JOB_SCRIPT: &str = r#"
|
|
20
|
+
if redis.call('SISMEMBER', KEYS[2], ARGV[1]) == 0 then return 0 end
|
|
21
|
+
redis.call('SET', KEYS[1], ARGV[2])
|
|
22
|
+
redis.call('SREM', KEYS[2], ARGV[1])
|
|
23
|
+
redis.call('SADD', KEYS[3], ARGV[1])
|
|
24
|
+
redis.call('ZREM', KEYS[4], ARGV[1])
|
|
25
|
+
return 1
|
|
26
|
+
"#;
|
|
27
|
+
|
|
9
28
|
impl RedisStorage {
|
|
29
|
+
/// Atomically claim a candidate job (Pending→Running) via [`CLAIM_JOB_SCRIPT`].
|
|
30
|
+
/// The caller must have already set `job.status = Running` and `started_at`.
|
|
31
|
+
/// Returns `false` if the job was concurrently cancelled/expired/claimed, so
|
|
32
|
+
/// the dequeue scan should skip it.
|
|
33
|
+
fn claim_pending(
|
|
34
|
+
&self,
|
|
35
|
+
conn: &mut redis::Connection,
|
|
36
|
+
job: &Job,
|
|
37
|
+
queue_key: &str,
|
|
38
|
+
) -> Result<bool> {
|
|
39
|
+
let job_json = serde_json::to_string(job).map_err(|e| QueueError::Other(e.to_string()))?;
|
|
40
|
+
let job_key = self.key(&["job", &job.id]);
|
|
41
|
+
let pending_status =
|
|
42
|
+
self.key(&["jobs", "status", &(JobStatus::Pending as i32).to_string()]);
|
|
43
|
+
let running_status =
|
|
44
|
+
self.key(&["jobs", "status", &(JobStatus::Running as i32).to_string()]);
|
|
45
|
+
let claimed: i32 = redis::Script::new(CLAIM_JOB_SCRIPT)
|
|
46
|
+
.key(&job_key)
|
|
47
|
+
.key(&pending_status)
|
|
48
|
+
.key(&running_status)
|
|
49
|
+
.key(queue_key)
|
|
50
|
+
.arg(&job.id)
|
|
51
|
+
.arg(&job_json)
|
|
52
|
+
.invoke(conn)
|
|
53
|
+
.map_err(map_err)?;
|
|
54
|
+
Ok(claimed == 1)
|
|
55
|
+
}
|
|
56
|
+
|
|
10
57
|
pub fn dequeue(
|
|
11
58
|
&self,
|
|
12
59
|
queue_name: &str,
|
|
@@ -101,14 +148,13 @@ impl RedisStorage {
|
|
|
101
148
|
}
|
|
102
149
|
}
|
|
103
150
|
|
|
104
|
-
// Claim the job
|
|
151
|
+
// Claim the job atomically; if we lost the race (cancelled / expired
|
|
152
|
+
// / claimed by another scheduler) skip to the next candidate.
|
|
105
153
|
job.status = JobStatus::Running;
|
|
106
154
|
job.started_at = Some(now);
|
|
107
|
-
self.
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
return Ok(Some(job));
|
|
155
|
+
if self.claim_pending(&mut conn, &job, &queue_key)? {
|
|
156
|
+
return Ok(Some(job));
|
|
157
|
+
}
|
|
112
158
|
}
|
|
113
159
|
|
|
114
160
|
Ok(None)
|
|
@@ -240,14 +286,13 @@ impl RedisStorage {
|
|
|
240
286
|
}
|
|
241
287
|
}
|
|
242
288
|
|
|
243
|
-
// Claim the job
|
|
289
|
+
// Claim the job atomically; skip candidates lost to a concurrent
|
|
290
|
+
// cancel / expire / claim instead of resurrecting them.
|
|
244
291
|
job.status = JobStatus::Running;
|
|
245
292
|
job.started_at = Some(now);
|
|
246
|
-
self.
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
claimed.push(job);
|
|
293
|
+
if self.claim_pending(&mut conn, &job, &queue_key)? {
|
|
294
|
+
claimed.push(job);
|
|
295
|
+
}
|
|
251
296
|
}
|
|
252
297
|
|
|
253
298
|
Ok(claimed)
|
{taskito-0.16.1 → taskito-0.16.2}/crates/taskito-core/src/storage/redis_backend/jobs/helpers.rs
RENAMED
|
@@ -2,10 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
use redis::Commands;
|
|
4
4
|
|
|
5
|
+
use super::dequeue_score;
|
|
5
6
|
use crate::error::{QueueError, Result};
|
|
6
7
|
use crate::job::{Job, JobStatus};
|
|
7
8
|
use crate::storage::redis_backend::{map_err, RedisStorage};
|
|
8
9
|
|
|
10
|
+
/// Lua: release a unique-key pointer only if it still points at `ARGV[1]`.
|
|
11
|
+
/// A newer job may have reused the same `unique_key` after this job left the
|
|
12
|
+
/// live indices, so an unconditional `DEL` would clobber the new job's dedup
|
|
13
|
+
/// lock. Mirrors `RELEASE_LOCK_SCRIPT` in `locks.rs`.
|
|
14
|
+
const RELEASE_UNIQUE_IF_OWNER: &str = r#"
|
|
15
|
+
if redis.call('GET', KEYS[1]) == ARGV[1] then
|
|
16
|
+
redis.call('DEL', KEYS[1])
|
|
17
|
+
return 1
|
|
18
|
+
end
|
|
19
|
+
return 0
|
|
20
|
+
"#;
|
|
21
|
+
|
|
9
22
|
impl RedisStorage {
|
|
10
23
|
pub(in crate::storage::redis_backend) fn load_job(
|
|
11
24
|
&self,
|
|
@@ -74,22 +87,71 @@ impl RedisStorage {
|
|
|
74
87
|
Ok(())
|
|
75
88
|
}
|
|
76
89
|
|
|
77
|
-
///
|
|
78
|
-
///
|
|
79
|
-
///
|
|
80
|
-
///
|
|
81
|
-
///
|
|
90
|
+
/// Reset a job to `Pending` and (re)insert it into the per-queue pending
|
|
91
|
+
/// zset in a single MULTI/EXEC. Folding the status-set move and the zset
|
|
92
|
+
/// add into one transaction means a crash can no longer strand the job as
|
|
93
|
+
/// `Pending` in the status set but absent from the queue zset (where it
|
|
94
|
+
/// would never be dequeued and never reaped).
|
|
82
95
|
///
|
|
83
|
-
///
|
|
84
|
-
///
|
|
85
|
-
|
|
86
|
-
pub(in crate::storage::redis_backend) fn archive_job_immediately(
|
|
96
|
+
/// The caller must have already set the job's `status = Pending`,
|
|
97
|
+
/// `scheduled_at`, and cleared `started_at`/`completed_at`/`error`.
|
|
98
|
+
pub(in crate::storage::redis_backend) fn requeue_pending(
|
|
87
99
|
&self,
|
|
88
100
|
conn: &mut redis::Connection,
|
|
89
101
|
job: &Job,
|
|
90
102
|
old_status: JobStatus,
|
|
91
103
|
) -> Result<()> {
|
|
92
104
|
let job_json = serde_json::to_string(job).map_err(|e| QueueError::Other(e.to_string()))?;
|
|
105
|
+
let job_key = self.key(&["job", &job.id]);
|
|
106
|
+
let old_status_key = self.key(&["jobs", "status", &(old_status as i32).to_string()]);
|
|
107
|
+
let pending_status_key =
|
|
108
|
+
self.key(&["jobs", "status", &(JobStatus::Pending as i32).to_string()]);
|
|
109
|
+
let queue_key = self.key(&["queue", &job.queue, "pending"]);
|
|
110
|
+
let score = dequeue_score(job.priority, job.scheduled_at);
|
|
111
|
+
|
|
112
|
+
let pipe = &mut redis::pipe();
|
|
113
|
+
pipe.atomic();
|
|
114
|
+
pipe.set(&job_key, &job_json);
|
|
115
|
+
if old_status != JobStatus::Pending {
|
|
116
|
+
pipe.srem(&old_status_key, &job.id);
|
|
117
|
+
pipe.sadd(&pending_status_key, &job.id);
|
|
118
|
+
}
|
|
119
|
+
pipe.zadd(&queue_key, &job.id, score);
|
|
120
|
+
pipe.query::<()>(conn).map_err(map_err)?;
|
|
121
|
+
|
|
122
|
+
Ok(())
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/// Release a job's unique-key pointer iff it still belongs to this job, via
|
|
126
|
+
/// an atomic compare-and-delete (mirrors `RELEASE_LOCK_SCRIPT`). Safe to
|
|
127
|
+
/// call when a newer job may have reused the same `unique_key`.
|
|
128
|
+
pub(in crate::storage::redis_backend) fn release_unique_key(
|
|
129
|
+
&self,
|
|
130
|
+
conn: &mut redis::Connection,
|
|
131
|
+
unique_key: &str,
|
|
132
|
+
job_id: &str,
|
|
133
|
+
) -> Result<()> {
|
|
134
|
+
let key = self.key(&["jobs", "unique", unique_key]);
|
|
135
|
+
redis::Script::new(RELEASE_UNIQUE_IF_OWNER)
|
|
136
|
+
.key(&key)
|
|
137
|
+
.arg(job_id)
|
|
138
|
+
.invoke::<i32>(conn)
|
|
139
|
+
.map_err(map_err)?;
|
|
140
|
+
Ok(())
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/// Append the live→archive command sequence to `pipe` (no MULTI/EXEC of its
|
|
144
|
+
/// own). Removes the job from the live indices and writes the archived row.
|
|
145
|
+
/// Shared by `archive_job_immediately` and `move_to_dlq` so the DLQ write and
|
|
146
|
+
/// the archive can commit in one transaction. The caller must have already
|
|
147
|
+
/// set the terminal `status`/`completed_at` and serialized `job_json`.
|
|
148
|
+
pub(in crate::storage::redis_backend) fn push_archive_ops(
|
|
149
|
+
&self,
|
|
150
|
+
pipe: &mut redis::Pipeline,
|
|
151
|
+
job: &Job,
|
|
152
|
+
old_status: JobStatus,
|
|
153
|
+
job_json: &str,
|
|
154
|
+
) {
|
|
93
155
|
let completed_at = job.completed_at.unwrap_or_else(crate::job::now_millis);
|
|
94
156
|
|
|
95
157
|
let job_key = self.key(&["job", &job.id]);
|
|
@@ -104,24 +166,38 @@ impl RedisStorage {
|
|
|
104
166
|
let archived_by_queue = self.key(&["archived", "by_queue", &job.queue]);
|
|
105
167
|
let archived_all = self.key(&["archived", "all"]);
|
|
106
168
|
|
|
107
|
-
//
|
|
108
|
-
//
|
|
109
|
-
|
|
110
|
-
pipe.
|
|
111
|
-
pipe.
|
|
112
|
-
pipe.srem(&
|
|
113
|
-
pipe.
|
|
114
|
-
pipe.srem(&by_task_key, &job.id);
|
|
115
|
-
pipe.zrem(&all_key, &job.id);
|
|
169
|
+
// Results are ignored so callers can query the pipe as `()` (or
|
|
170
|
+
// `Option<()>` inside a WATCH transaction).
|
|
171
|
+
pipe.del(&job_key).ignore();
|
|
172
|
+
pipe.srem(&status_key, &job.id).ignore();
|
|
173
|
+
pipe.srem(&by_queue_key, &job.id).ignore();
|
|
174
|
+
pipe.srem(&by_task_key, &job.id).ignore();
|
|
175
|
+
pipe.zrem(&all_key, &job.id).ignore();
|
|
116
176
|
// Pending jobs still sit in the per-queue pending zset; running jobs
|
|
117
177
|
// were removed at dequeue, so only remove on a Pending→terminal move.
|
|
118
178
|
if old_status == JobStatus::Pending {
|
|
119
|
-
pipe.zrem(&pending_key, &job.id);
|
|
179
|
+
pipe.zrem(&pending_key, &job.id).ignore();
|
|
120
180
|
}
|
|
121
|
-
pipe.set(&archived_key,
|
|
122
|
-
pipe.sadd(&archived_status_key, &job.id);
|
|
123
|
-
pipe.sadd(&archived_by_queue, &job.id);
|
|
124
|
-
pipe.zadd(&archived_all, &job.id, completed_at as f64)
|
|
181
|
+
pipe.set(&archived_key, job_json).ignore();
|
|
182
|
+
pipe.sadd(&archived_status_key, &job.id).ignore();
|
|
183
|
+
pipe.sadd(&archived_by_queue, &job.id).ignore();
|
|
184
|
+
pipe.zadd(&archived_all, &job.id, completed_at as f64)
|
|
185
|
+
.ignore();
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/// Move a terminal job out of the live indices into the archive in one
|
|
189
|
+
/// atomic pipeline (`.atomic()` MULTI/EXEC), so it is never observable in
|
|
190
|
+
/// both the live and archived indices at once.
|
|
191
|
+
pub(in crate::storage::redis_backend) fn archive_job_immediately(
|
|
192
|
+
&self,
|
|
193
|
+
conn: &mut redis::Connection,
|
|
194
|
+
job: &Job,
|
|
195
|
+
old_status: JobStatus,
|
|
196
|
+
) -> Result<()> {
|
|
197
|
+
let job_json = serde_json::to_string(job).map_err(|e| QueueError::Other(e.to_string()))?;
|
|
198
|
+
let pipe = &mut redis::pipe();
|
|
199
|
+
pipe.atomic();
|
|
200
|
+
self.push_archive_ops(pipe, job, old_status, &job_json);
|
|
125
201
|
pipe.query::<()>(conn).map_err(map_err)?;
|
|
126
202
|
|
|
127
203
|
Ok(())
|
|
@@ -153,21 +229,15 @@ impl RedisStorage {
|
|
|
153
229
|
pipe.del(&errors_key);
|
|
154
230
|
pipe.del(&deps_key);
|
|
155
231
|
pipe.del(&dependents_key);
|
|
232
|
+
pipe.query::<()>(conn).map_err(map_err)?;
|
|
156
233
|
|
|
157
|
-
//
|
|
158
|
-
// `enqueue_unique`
|
|
159
|
-
//
|
|
160
|
-
// and deleting the pointer would clobber the new job's lock.
|
|
234
|
+
// Release the unique-key pointer through the atomic compare-and-delete so
|
|
235
|
+
// a `enqueue_unique` that reused the key between a plain GET and DEL can't
|
|
236
|
+
// have its lock clobbered.
|
|
161
237
|
if let Some(ref uk) = job.unique_key {
|
|
162
|
-
|
|
163
|
-
let owner: Option<String> = conn.get(&unique_key).map_err(map_err)?;
|
|
164
|
-
if owner.as_deref() == Some(job.id.as_str()) {
|
|
165
|
-
pipe.del(&unique_key);
|
|
166
|
-
}
|
|
238
|
+
self.release_unique_key(conn, uk, &job.id)?;
|
|
167
239
|
}
|
|
168
240
|
|
|
169
|
-
pipe.query::<()>(conn).map_err(map_err)?;
|
|
170
|
-
|
|
171
241
|
Ok(())
|
|
172
242
|
}
|
|
173
243
|
}
|