toro 🐂
An async-first, Redis-backed job queue for Python. Every state transition is
an atomic Lua script; producing and processing are asyncio end to end.
pip install toro-queue # the import name is `toro`
Installed as
toro-queueon PyPI (the nametorowas taken), but youimport toro. See the docs for the architecture, the reliability model, and the detailed guides.
Pairs with matador, a live web dashboard for your queues.
Why toro
- Async-native. Enqueue and process with
async/await- no thread pools, no sync bridge. A natural fit for FastAPI, aiohttp, or any asyncio app. - Atomic by construction. Claims, retries, promotions and finishes are Lua scripts, so a job can't be lost or double-committed between two round trips.
- At-least-once delivery. Per-job locks + a background mark-and-sweep recover jobs from workers that crashed - without the visibility-timeout double-delivery trap of some other queues.
- Typed. Ships
py.typed; the public API is fully annotated.
Features
| Enqueue | delayed jobs, global priorities (FIFO within a band) |
| Retries | fixed or exponential backoff, capped attempts |
| Schedules | repeatable cron and fixed-interval (every) jobs |
| Flows | parent/child job trees: fan-out/fan-in, failure policies, flow-aware retry |
| Rate limiting | queue-wide token bucket shared across all workers |
| Dedup | custom (idempotent) job ids + a throttle window ({id, ttl}) |
| Auto-removal | keep the last N and/or finished-within-age completed/failed |
| Reliability | per-job locks, lock renewal, stalled-job recovery |
| Observability | progress, per-job logs, lifecycle events, await result() |
| Lifecycle | pause / resume, graceful shutdown that drains in-flight jobs |
| Dashboard | matador - a live web UI |
Quick start
import asyncio
from toro import Queue, Worker
async def main():
queue = Queue("emails")
await queue.add("welcome", {"to": "ada@example.com"})
async def process(job):
print("sending", job.data)
return {"ok": True}
worker = Worker("emails", process, concurrency=8)
worker.on("completed", lambda job, result: print("done", job.id))
await worker.run()
asyncio.run(main())
A taste of the options
# Priorities, delay, and retry-with-backoff
await queue.add("report", data, priority=10, delay=5000,
attempts=5, backoff={"type": "exponential", "delay": 1000})
# Idempotent custom id (a second add with the same id is ignored)
await queue.add("charge", data, job_id="order-1234")
# A repeatable schedule (cron or every-N-ms); "run now" with trigger_scheduler
await queue.add_scheduler("nightly-rollup", cron="0 0 * * *")
# A flow: children run first (fan-out), the parent runs on their results (fan-in)
from toro import FlowChild as c
report = await queue.add_flow("report", {"q": 3},
children=[c("fetch", {"shard": i}) for i in range(3)])
# Queue-wide rate limit: at most 100 jobs / second across every worker
worker = Worker("emails", process, rate_limit={"max": 100, "duration": 1000})
# Wait for a result from the producer side
job = await queue.add("resize", {"src": "a.png"})
print(await job.result(timeout=30))
Flows
A flow enqueues a parent and its children as one atomic tree. The children run first (fan-out, nested arbitrarily); the parent parks until every child has settled, then runs and reads their results (fan-in). One primitive covers fan-out/fan-in and chained steps, with per-child failure policies and flow-aware retry that recovers a whole failed flow in one shot. Full guide: docs/flows.md.
Develop
Managed with uv; the Astral toolchain throughout.
uv sync # venv + deps + dev group
uv run ruff check . # lint (strict: select = ALL)
uv run ruff format . # format
uv run ty check # type check
uv run pytest -m "unit or integration" # tests (integration needs Redis on :6379)
uv run python examples/basic.py
The suite is a pyramid - -m unit (fast, no Redis), -m integration (Redis),
and -m load (the open-loop benchmark harness in tests/load/).
License
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file toro_queue-0.5.0.tar.gz.
File metadata
- Download URL: toro_queue-0.5.0.tar.gz
- Upload date:
- Size: 146.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
293f325728a71975656a80ace07aaf9c2ee921b3e555bf4c29e5342d399bdbbb
|
|
| MD5 |
2d6842cb116e89057f4f411cca3d07ef
|
|
| BLAKE2b-256 |
d307985139e26e08880dd1e79677479b89c7f8d71cac8bfababcccbab0ff8137
|
Provenance
The following attestation bundles were made for toro_queue-0.5.0.tar.gz:
Publisher:
release.yml on ilovepixelart/toro
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
toro_queue-0.5.0.tar.gz -
Subject digest:
293f325728a71975656a80ace07aaf9c2ee921b3e555bf4c29e5342d399bdbbb - Sigstore transparency entry: 1931016799
- Sigstore integration time:
-
Permalink:
ilovepixelart/toro@838b6145f8567515520b63ac763c68d5c079997e -
Branch / Tag:
refs/tags/v0.5.0 - Owner: https://github.com/ilovepixelart
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@838b6145f8567515520b63ac763c68d5c079997e -
Trigger Event:
push
-
Statement type:
File details
Details for the file toro_queue-0.5.0-py3-none-any.whl.
File metadata
- Download URL: toro_queue-0.5.0-py3-none-any.whl
- Upload date:
- Size: 47.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b447dba7eb1a709c28f58860c7f6e421a724f7079e264dd50d2dce091d1a7d69
|
|
| MD5 |
272268aaf5cfeef9a5f60e3dc9a5f724
|
|
| BLAKE2b-256 |
fd4f71ee791fe6f0fced48ba74d15c7990ad396d6a28f5971bf1af3e8b18f887
|
Provenance
The following attestation bundles were made for toro_queue-0.5.0-py3-none-any.whl:
Publisher:
release.yml on ilovepixelart/toro
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
toro_queue-0.5.0-py3-none-any.whl -
Subject digest:
b447dba7eb1a709c28f58860c7f6e421a724f7079e264dd50d2dce091d1a7d69 - Sigstore transparency entry: 1931016970
- Sigstore integration time:
-
Permalink:
ilovepixelart/toro@838b6145f8567515520b63ac763c68d5c079997e -
Branch / Tag:
refs/tags/v0.5.0 - Owner: https://github.com/ilovepixelart
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@838b6145f8567515520b63ac763c68d5c079997e -
Trigger Event:
push
-
Statement type: