Skip to main content

Background job queue for Python. Built for AI pipelines.

Project description

Viscacha

Background jobs for Python. Built for AI pipelines — every job crash-safe, traceable, and retriable.

from viscacha import Client, Worker

client = Client()
worker = Worker(client)

@worker.job("greet")
def greet(name: str) -> dict:
    return {"message": f"Hello, {name}!"}

worker.run(blocking=False)

handle = client.enqueue("greet", name="Alice")
result = handle.wait()
print(result.result)  # {'message': 'Hello, Alice!'}

No broker. No Redis. No Docker. Just Python.


Install

pip install uv
uv pip install -e .

Requires Python 3.10+.


How it works

  1. Submit a job
  2. A worker function runs it
  3. Get the result or inspect what happened
handle = client.enqueue("send_email", to="alice@example.com")

result = handle.wait(timeout=30)  # raises TimeoutError if it doesn't finish
print(result.status)   # 'done' | 'failed' | 'cancelled'
print(result.result)   # return value of the job function
print(result.error)    # set if failed, else None

handle.cancel()        # cancel a pending job

client.jobs()               # list all jobs
client.jobs(status="done")  # filter by status
client.get(handle.id)       # get one by ID

Guarantees

  • No lost jobs — a job stays in the queue until a worker completes it
  • Safe retries — transient failures retry automatically
  • Full traceability — every job logged with type, args, result, retries, error
  • Crash-safe — if a worker dies mid-job, the lease expires and the job returns to the queue

AI pipelines

Each Claude call is a job. Workers run in parallel. Failures retry automatically.

import anthropic
from viscacha import Client, Worker

client = Client()
worker = Worker(client)
ai = anthropic.Anthropic()

@worker.job("classify_ticket", max_retries=2)
def classify_ticket(title: str, body: str) -> dict:
    response = ai.messages.create(
        model="claude-haiku-4-5-20251001",
        max_tokens=120,
        messages=[{"role": "user", "content": f"Classify: {title}\n{body}"}],
    )
    return {"category": "bug", "priority": "high"}

worker.run(blocking=False)

handles = [client.enqueue("classify_ticket", title=t, body=b) for t, b in tickets]
results = [h.wait(timeout=30) for h in handles]
ANTHROPIC_API_KEY=sk-... python demos/demo_ai_jobs.py

Any function works

Email, HTTP calls, reports, transforms — a worker is just a function.

@worker.job("send_email")
def send_email(to: str, subject: str, html: str) -> dict:
    return {"to": to, "sent": True}

client.enqueue("send_email", to="bob@example.com", subject="Order confirmed", html="...")
python demos/demo_email_jobs.py  # dry-run, no SMTP needed

Retries and crash recovery

@worker.job("call_api", max_retries=5, lease_ttl=60.0)
def call_api(endpoint: str) -> dict:
    response = requests.get(endpoint, timeout=10)
    response.raise_for_status()
    return response.json()

max_retries — retries on any exception (default 3)
lease_ttl — seconds before a stalled job is reclaimed (default 30)


Persistence

client = Client(log_path="jobs.jsonl")

Append-only log. Jobs survive restarts.


HTTP API

Expose jobs over HTTP so workers can run anywhere:

from viscacha import Client
from viscacha.server import create_app
import uvicorn

app = create_app(Client(log_path="jobs.jsonl"))
uvicorn.run(app, host="0.0.0.0", port=8000)
curl -X POST http://localhost:8000/jobs \
  -H "Content-Type: application/json" \
  -d '{"job_type": "greet", "args": {"name": "Alice"}}'

curl http://localhost:8000/jobs?status=done

Under the hood

Jobs are tuples in an append-only tuple space. Workers claim jobs via leases — if a worker crashes, the lease expires and the job returns to the queue automatically. The coordination layer handles ordering, crash safety, and observability. Viscacha is a thin API on top.


Roadmap

  • Priority queues
  • Job chaining / workflows
  • Web dashboard
  • Scheduled / cron jobs
  • Distributed workers (multi-process, multi-host)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

viscacha-0.2.0-py3-none-any.whl (29.3 kB view details)

Uploaded Python 3

File details

Details for the file viscacha-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: viscacha-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 29.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for viscacha-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3025a3564b5aae0b29b10d98509f7abef8cf15bd3644b73d1e85b8b4ecb63c4d
MD5 47a70f876b2bf68de28482971ff78a4f
BLAKE2b-256 7cffca6c8092b9378976f692f56d35e377770cda99d7c3bb53a32c24ecff5454

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page