v0.1.10  ·  python 3.11+  ·  MIT

Queue a task.
Three lines of Code.

Three primitives: @task, dispatch(), and a worker process. Retries, timeouts, crash recovery — without the framework.

$ pip install tarsq → no config. just redis.
tasks.py
python
from tarsq import task, dispatch @task("send_email") async def send_email(ctx, payload):     mailer = ctx["mailer"]     await mailer.send(payload["email"]) dispatch("send_email", payload={"email": "user@example.com"})
~/app — tarsq --app tasks --workers 5
zsh

The whole feature list.
Read it in 90 seconds.

Workers survive their own failures.

Crash → restart with backoff. --workers 8 fills your cores. Graceful shutdown on SIGTERM drains in-flight jobs — nothing dropped.

$ tarsq --app myapp.tasks --workers 8

Retry only what should retry.

Failures retry with exponential backoff — 2s, 4s, 8s. Three attempts before a job is marked failed. The worker moves on either way.

# worker-0 RETRY send_email — retrying in 2s (attempt 1/3)

One DB pool. All tasks.

Initialize your connection pool once at worker startup. Every task receives it via ctx — no reconnection, no globals.

async def on_startup(ctx):
  ctx["db"] = await asyncpg.create_pool(url)

Timeouts that actually fire.

--timeout 30 means 30 seconds — hard limit, not a hint. Task cancelled, marked failed, worker keeps running.

$ tarsq --app myapp.tasks --timeout 30

Three steps.
That's the whole API.

No client SDK to manage. No broker config to memorize. Define tasks where they live, dispatch them anywhere they're needed.

Tag it with @task.

One decorator, one name string. That's how tarsq knows what to run when a job arrives.

@task("resize_image")
async def resize(ctx, payload):
  # …

Enqueue with dispatch().

Works from any Python process — web handler, CLI script, cron job, or another task. No shared instance required.

dispatch("resize_image",
  payload={"id": 42})

Workers handle the rest.

tarsq worker dequeues jobs, runs them with your retry and timeout config, and logs every state change.

$ tarsq --app tasks
› picked up resize_image
› completed resize_image — 1.2s

Your Redis is already running.

MIT licensed. pip install is the entire setup.