Dispatch¶
zeroth.platform.dispatch ¶
Durable run dispatch infrastructure: lease claiming and ARQ wakeups.
LeaseManager owns the SQL lease protocol over the runs table; the ARQ
helpers provide best-effort wakeup signals so workers can skip a poll
interval. The run worker that drives claimed runs through the orchestrator is
runtime code and lives in :mod:zeroth.runtime.orchestration.run_worker.
LeaseManager
dataclass
¶
Manages worker leases on runs stored in an async database.
A lease is an exclusive claim on a run. Workers use leases to prevent
two concurrent workers from both executing the same run. Leases expire
after lease_duration_seconds so a crashed worker's work can be reclaimed.
claim_pending
async
¶
claim_pending(
deployment_ref: str,
worker_id: str,
*,
tenant_id: str | None = None,
workspace_id: str | None | object = _UNSCOPED_WORKSPACE,
max_concurrency: int | None = None,
) -> str | None
Atomically claim one PENDING run for this worker.
Dispatches to _claim_pending_pg (Postgres) or
_claim_pending_sqlite (SQLite) based on the database backend.
Returns the run_id that was claimed, or None if no work is available. The claimed run's status is left as PENDING -- the worker transitions it to RUNNING once execution actually starts.
claim_pending_result
async
¶
claim_pending_result(
deployment_ref: str,
worker_id: str,
*,
tenant_id: str | None = None,
workspace_id: str | None | object = _UNSCOPED_WORKSPACE,
max_concurrency: int | None = None,
) -> LeaseClaimResult
Claim once and return saturation observed by this exact call.
claim_orphaned
async
¶
claim_orphaned(
deployment_ref: str,
worker_id: str,
*,
tenant_id: str | None = None,
workspace_id: str | None | object = _UNSCOPED_WORKSPACE,
max_concurrency: int | None = None,
claim_limit: int | None = None,
) -> list[str]
Claim all RUNNING runs with expired leases for this deployment.
Called at worker startup to recover work abandoned by crashed workers.
Sets recovery_checkpoint_id to the latest checkpoint for each
claimed run so the worker knows where to resume.
claim_orphaned_result
async
¶
claim_orphaned_result(
deployment_ref: str,
worker_id: str,
*,
tenant_id: str | None = None,
workspace_id: str | None | object = _UNSCOPED_WORKSPACE,
max_concurrency: int | None = None,
claim_limit: int | None = None,
) -> _OrphanClaimResult
Claim expired RUNNING runs and distinguish saturation from exhaustion.
renew_lease
async
¶
renew_lease(
run_id: str,
worker_id: str,
*,
generation: int | None = None,
tenant_id: str | None = None,
workspace_id: str | None | object = _UNSCOPED_WORKSPACE,
) -> bool
Extend the lease expiry for an active run.
Returns True if the lease was renewed (i.e. we still own it), False if another worker has taken over or the run no longer exists.
generation qualifies the renewal on top of ownership. Worker ids are
fresh per process, so owner-qualification alone already catches takeover
by a different worker; the generation additionally catches the case
where the lease was released and re-acquired, and is what the caller
must then present to :meth:commit_fenced.
current_generation
async
¶
current_generation(
run_id: str,
*,
tenant_id: str | None = None,
workspace_id: str | None | object = _UNSCOPED_WORKSPACE,
) -> int | None
The run's current lease generation, or None if the run is unknown.
current_holder
async
¶
current_holder(
run_id: str,
*,
tenant_id: str | None = None,
workspace_id: str | None | object = _UNSCOPED_WORKSPACE,
) -> str | None
The worker id currently holding the run's lease, or None.
A write fence is only meaningful for the worker that actually holds the lease; installing one without ownership would reject every save.
commit_fenced
async
¶
commit_fenced(
run_id: str,
worker_id: str,
*,
generation: int,
tenant_id: str | None = None,
workspace_id: str | None | object = _UNSCOPED_WORKSPACE,
metrics_collector: object | None = None,
**columns: object,
) -> bool
Apply a run-state write only if the caller still holds the lease.
The fence is part of the UPDATE predicate rather than a preceding check, because a check-then-write leaves a window in which ownership can move between the two statements -- precisely the race this exists to close.
Returns True when the write landed, False when the lease expired or a newer generation (or a different owner) superseded the caller.
release_lease
async
¶
release_lease(
run_id: str,
worker_id: str,
*,
generation: int,
tenant_id: str | None = None,
workspace_id: str | None | object = _UNSCOPED_WORKSPACE,
) -> bool
Clear only the exact owned lease generation after execution.
hand_back_to_pending
async
¶
hand_back_to_pending(
run_id: str,
worker_id: str,
*,
generation: int,
tenant_id: str | None = None,
workspace_id: str | None | object = _UNSCOPED_WORKSPACE,
) -> bool
Atomically return one exact RUNNING lease generation to PENDING.
expire_recovery_lease
async
¶
expire_recovery_lease(
run_id: str,
worker_id: str,
*,
generation: int,
tenant_id: str | None = None,
workspace_id: str | None | object = _UNSCOPED_WORKSPACE,
) -> bool
Make owned recovery work immediately reclaimable without losing its checkpoint.
clear_lease
async
¶
clear_lease(
run_id: str,
*,
tenant_id: str | None = None,
workspace_id: str | None | object = _UNSCOPED_WORKSPACE,
) -> None
Clear the lease columns regardless of the current lease owner.
get_recovery_checkpoint_id
async
¶
get_recovery_checkpoint_id(
run_id: str,
*,
tenant_id: str | None = None,
workspace_id: str | None | object = _UNSCOPED_WORKSPACE,
) -> str | None
Return the recovery_checkpoint_id stored on the run, if any.
arq_settings_from_zeroth ¶
Convert ZerothSettings.redis to ARQ RedisSettings.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
redis_settings
|
Any
|
A RedisSettings instance from zeroth.platform.config.settings. |
required |
Returns:
| Type | Description |
|---|---|
Any
|
An arq.connections.RedisSettings instance. |
create_arq_pool
async
¶
Create an ARQ connection pool from Zeroth Redis settings.
Returns None if ARQ or Redis is unavailable.
enqueue_wakeup
async
¶
Best-effort wakeup enqueue. Never raises.
Enqueues a minimal ARQ job carrying only the run_id as a signal for a worker to check the lease store. The job itself does nothing -- the act of receiving it IS the wakeup signal.
run_arq_consumer
async
¶
Run ARQ consumer as a background task.
Calls on_wakeup(run_id) for each wakeup signal received. Runs until cancelled. Designed to be wrapped in asyncio.create_task.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
redis_settings
|
Any
|
Zeroth RedisSettings (will be converted to ARQ format). |
required |
on_wakeup
|
Callable[[str], Awaitable[None]]
|
Async callback invoked when a wakeup signal arrives. |
required |
zeroth.runtime.orchestration.run_worker ¶
Durable run worker that replaces asyncio.create_task dispatch.
A RunWorker polls SQLite for PENDING runs, claims them via lease, drives them through the RuntimeOrchestrator, and releases the lease on completion. On startup it reclaims any orphaned RUNNING runs whose leases have expired.
The worker runs as a single asyncio background task started in the app lifespan. Graceful shutdown cancels the poll loop without interrupting runs that are currently executing (the semaphore ensures bounded concurrency).
RunWorker
dataclass
¶
RunWorker(
deployment_ref: str,
run_repository: RunRepository,
orchestrator: RuntimeOrchestrator,
graph: Graph,
lease_manager: LeaseManager,
tenant_id: str | None = None,
workspace_id: str | None = None,
max_concurrency: int = 8,
poll_interval: float = 0.5,
orphan_sweep_interval: float = 5.0,
worker_id: str = _new_worker_id(),
dead_letter_manager: DeadLetterManager | None = None,
metrics_collector: MetricsCollector | None = None,
shutdown_timeout: float = 30.0,
)
Long-lived worker that drives PENDING runs to completion.
Attributes:
| Name | Type | Description |
|---|---|---|
deployment_ref |
str
|
The deployment this worker serves. |
run_repository |
RunRepository
|
Used to load/transition runs. |
orchestrator |
RuntimeOrchestrator
|
Drives execution for each run. |
graph |
Graph
|
The deployment graph passed to the orchestrator. |
lease_manager |
LeaseManager
|
Manages SQLite-backed leases. |
max_concurrency |
int
|
Maximum simultaneous runs (default 8). |
poll_interval |
float
|
Seconds between poll ticks when idle (default 0.5). |
worker_id |
str
|
Unique ID for this worker instance. |
dead_letter_manager |
DeadLetterManager | None
|
Optional; marks repeatedly-failing runs as dead-letter. |
metrics_collector |
MetricsCollector | None
|
Optional; records execution metrics. |
interrupt_active_run
async
¶
Stop this worker's active drive without changing persisted status.
handle_wakeup
async
¶
ARQ wakeup callback -- attempt to claim from DB immediately.
The run_id is informational only; the worker always claims from the lease store (not from the ARQ job payload) per D-06.
graceful_shutdown
async
¶
Wait for in-flight tasks then release remaining leases to PENDING.
Called on SIGTERM. Steps: 1. Set stopping flag so poll_loop exits cleanly 2. Wait for active tasks to complete (up to shutdown_timeout) 3. For any tasks still running, cancel them and release their leases back to PENDING so another worker can claim them