What's new in V2
V1 is one job, one attempt, gone when the process exits. V2 adds durable,
multi-step workflows on top of it — additively. Nothing about Queue,
Job, Priority, or how V1 behaves has changed; a V1 consumer who never
touches workflows sees zero difference after upgrading.
New: durable workflows
Section titled “New: durable workflows”Workflow/StepDef. An ordered list of steps under a stable id, each with its ownRetryPolicyand optional timeout.WorkflowEngine. Drives a workflow’s steps through the sameQueueV1 jobs use — it’s the only thing that callsQueue::pushfor a workflow step. Retries a failed step per itsRetryPolicy, entirely on its own;Queueitself stays exactly as retry-agnostic as it’s always been.- Waiting on external input. A step can return
WaitForInputto block on something outside the process — an approval, a webhook, a human.runpauses the whole workflow there rather than failing it;WorkflowEngine::resumesupplies the missing input and continues through the remaining steps. - Non-retryable failures. A step can return
NonRetryableto fail the whole workflow immediately, skipping the rest of itsRetryPolicy’s attempts — for errors that retrying can’t fix (bad input, a 4xx from a downstream API). - Per-step timeouts.
StepDef::timeoutis now enforced — an attempt that runs past its timeout is treated as a failure and retried like any other. The original job keeps running in the background after a timeout; see Durable store and the CHANGELOG for the exact tradeoff this makes. - Cancellation.
WorkflowEngine::cancelidempotently stops a workflow. A step attempt already pushed to the queue isn’t aborted, but no further step runs afterward. DurableStore. A trait for where step status and event history live.SqliteStoreships as the one concrete implementation, behind the optionalsqliteCargo feature — off by default, so a consumer who only wants the rawQueuenever pulls inrusqlite. It also records each event’s timestamp (SqliteStore::load_events_with_timestamps), with existing databases migrated automatically.- Recovery.
agentq::recoverfinds steps whose worker died mid-lease (viaDurableStore::expired_leases) and re-admits them, once you’ve re-registered the workflow’s bodies withWorkflowEngine:: register_workflowfor the current process.
See the Durable workflows guide for how the pieces fit
together, and Durable store for how
SqliteStore is actually structured.
Install
Section titled “Install”[dependencies]agentq = { version = "0.2", features = ["sqlite"] }Without the sqlite feature, nothing changes from V1 — rusqlite never
enters your dependency tree, and none of the new public types cost you
anything you don’t use.
What didn’t change
Section titled “What didn’t change”Queue,Job,Priority, lanes, backpressure, idempotency — identical to V1. See Guarantees for what still does and doesn’t hold at that layer.- The raw
Queuestill does not persist anything or retry automatically. Those are workflow-layer features now, notQueuefeatures — see Upcoming for what’s still actually planned forQueueitself.