ElephantQ - PostgreSQL-only async job queue - built for developer happiness.
Project description
ElephantQ
PostgreSQL-first background jobs for Python.
ElephantQ is a modern, async-first job queue that uses PostgreSQL as the only backend. No Redis, no broker services, no operational sprawl. You get reliable queues, retries, scheduling, and a dashboard in a single package.
Why ElephantQ
- One backend: PostgreSQL only. No Redis or broker to deploy or maintain.
- Async-native API: use
async defjobs andawaitenqueue. - Explicit worker model: predictable production behavior, easy to scale.
- Built-in features in the same package (opt-in flags).
- Strong DX: clean CLI, clear job discovery, minimal boilerplate.
- Scales well: uses Postgres
LISTEN/NOTIFYfor fast wakeups and row locking for safe concurrency.
Quick Start
Prerequisites: PostgreSQL
# 1. Install
pip install elephantq
# 2. Set your database URL
export ELEPHANTQ_DATABASE_URL="postgresql://localhost/your_db"
# 3. Initialize database (creates tables)
elephantq setup
Architecture at a Glance
- Your app enqueues jobs directly into PostgreSQL; no broker, no separate result store.
- Workers poll with
LISTEN/NOTIFYplusFOR UPDATE SKIP LOCKED; horizontal workers never fight over rows. - Feature flags gate dashboard, metrics, dead-letter, scheduling, signing, timeouts, dependencies, and more.
Design Choices
- PostgreSQL-only stack keeps reliability predictable and operations simple while leveraging existing transactions.
- Explicit scheduler command (
elephantq scheduler) runs only when you need recurring/cron jobs. For development,elephantq devbundles worker + scheduler + dashboard. - Feature flag gating keeps
elephantq.enqueue,elephantq.start, and the global API lean even though dashboard, metrics, signing, and webhooks live in the same repository. - Built-in observability: CLI reports job counts, the dashboard paints job/queue metrics, and optional metrics/Prometheus data live under
elephantq.features.metrics.
Fluent Scheduling API
ElephantQ offers fluent builders so complex scheduling logic stays readable.
Use elephantq.features.recurring.daily().at("09:00").high_priority().schedule(report_job) for expressive recurring flows,
or elephantq.features.scheduling.schedule_job(task).in_hours(2).enqueue(arg=...) for ad-hoc delayed execution.
Batches via elephantq.features.scheduling.create_batch().enqueue_all([...]) keep coordinated enqueues atomic and traceable across the same PostgreSQL transaction.
Minimal App (FastAPI)
import elephantq
from fastapi import FastAPI
app = FastAPI()
elephantq.configure(database_url="postgresql://localhost/myapp")
@elephantq.job()
async def process_upload(file_path: str):
print(f"Processing {file_path}")
@app.post("/upload")
async def upload_file(file_path: str):
job_id = await elephantq.enqueue(process_upload, file_path=file_path)
return {"job_id": job_id}
Run Workers
ElephantQ workers always run as a separate process.
# Terminal 1: Your app
uvicorn app:app
# Terminal 2: Workers (needs discovery)
export ELEPHANTQ_JOBS_MODULES="app"
elephantq start --concurrency 4
ELEPHANTQ_JOBS_MODULES drives the discovery snippet shown above. Run the scheduler daemon when you need recurring/crontab-style jobs—just like Celery keeps Beat and workers separate, ElephantQ keeps recurring work in a dedicated process so workers stay focused on execution. citeturn0search2
ELEPHANTQ_SCHEDULING_ENABLED=true elephantq scheduler
The dashboard lives behind ELEPHANTQ_DASHBOARD_ENABLED=true elephantq dashboard. Add ELEPHANTQ_DASHBOARD_WRITE_ENABLED=true if you need retry/delete/cancel buttons.
Dashboard Preview
ElephantQ vs Alternatives
| Aspect | Celery | RQ | ElephantQ |
|---|---|---|---|
| Backend | Redis/RabbitMQ required | Redis required | ✅ PostgreSQL only |
| Scheduling | Separate beat process |
External scheduler | ✅ Built-in scheduling |
| Concurrency | Worker pools + ack tuning | Controlled by Redis | Queue routing + unique jobs + dependency/timeouts |
| Observability | Flower/exporter dashboards | rq-dashboard | Built-in dashboard + metrics |
| Getting started | More setup | Moderate setup | ✅ Minutes to first job |
Examples (Practical)
Reliable Retries (Backoff)
import elephantq
@elephantq.job(retries=5, retry_delay=1, retry_backoff=True, retry_max_delay=30)
async def resilient_task(user_id: int):
...
Queue Routing
import elephantq
@elephantq.job(queue="emails")
async def send_email(to: str):
...
@elephantq.job(queue="media")
async def transcode_video(video_id: str):
...
# Process only specific queues
elephantq start --queues emails,media
Delayed Jobs (One-Off Scheduling)
import elephantq
@elephantq.job()
async def remind_user(user_id: int):
...
# Run in 10 minutes
await elephantq.schedule(remind_user, run_in=600, user_id=42)
Recurring Jobs (Cron)
import elephantq
after_midnight = "0 2 * * *"
@elephantq.job()
async def nightly_report():
...
await elephantq.features.recurring.cron(after_midnight).schedule(nightly_report)
Make sure ELEPHANTQ_SCHEDULING_ENABLED=true is set when using recurring jobs.
Instance-Based API (Multi-tenant or Separate DBs)
from elephantq import ElephantQ
billing = ElephantQ(database_url="postgresql://localhost/billing")
@billing.job()
async def invoice_customer(customer_id: int):
...
await billing.enqueue(invoice_customer, customer_id=123)
Examples Directory
Runnable examples live in examples/:
examples/basic_app.py– minimal FastAPI enqueue flowexamples/recurring_jobs.py– recurring scheduler patternsexamples/queue_routing.py– multi-queue routing and worker configexamples/file_processing.py– background file processing patternexamples/webhook_delivery.py– webhook delivery smoke example
Queue Design Tips
- Use separate queues for different workloads (e.g.,
emails,media,billing). - Keep job payloads small; store large blobs elsewhere and pass IDs.
- Use retries with backoff for flaky external APIs.
- Start with 1–4 workers locally; scale by adding worker processes.
Optional Features (Same Package)
Advanced features live under elephantq.features and are opt-in via flags. Core job APIs (job, enqueue, schedule, workers) remain in the main package. The dashboard and monitoring features also require their optional dependencies (see extras below).
pip install elephantq[dashboard]
pip install elephantq[monitoring]
pip install elephantq[all]
Enable feature flags:
export ELEPHANTQ_DASHBOARD_ENABLED=true # enable dashboard UI
export ELEPHANTQ_DASHBOARD_WRITE_ENABLED=true # allow retry/delete actions
export ELEPHANTQ_SCHEDULING_ENABLED=true # recurring + delayed jobs
export ELEPHANTQ_DEAD_LETTER_QUEUE_ENABLED=true # dead letter queue
export ELEPHANTQ_METRICS_ENABLED=true # metrics endpoints
export ELEPHANTQ_LOGGING_ENABLED=true # structured logging
export ELEPHANTQ_WEBHOOKS_ENABLED=true # webhooks on job events
export ELEPHANTQ_DEPENDENCIES_ENABLED=true # job dependencies
export ELEPHANTQ_TIMEOUTS_ENABLED=true # job timeouts
export ELEPHANTQ_SIGNING_ENABLED=true # optional helpers (signing, secrets utils)
Example usage:
import elephantq
metrics = await elephantq.features.metrics.get_system_metrics()
stats = await elephantq.features.dead_letter.get_stats()
Troubleshooting
"Job not registered"
If the worker says a job is not registered, it means the worker did not import your module.
✅ Fix:
export ELEPHANTQ_JOBS_MODULES="your_app_module"
elephantq start
CLI
elephantq setup
elephantq start --concurrency 4 --queues default,urgent
elephantq scheduler
elephantq dashboard --port 6161 # read-only by default
elephantq metrics --hours 24
elephantq dead-letter list
Documentation
docs/getting-started.mddocs/cli.mddocs/scheduling.mddocs/features.mddocs/production.md
Project details
Release history Release notifications | RSS feed
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 elephantq-0.1.1.tar.gz.
File metadata
- Download URL: elephantq-0.1.1.tar.gz
- Upload date:
- Size: 108.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f470fe552d60f225a0f61ce3ba59a24385a1d33694d6155add4a845f2fad9e34
|
|
| MD5 |
5a76d9d94814f67d8d7389213a7efa9d
|
|
| BLAKE2b-256 |
a88f0f3e63dafd02ae3d35bf91b65a522a77592f52b4a9cad903251a96351aa3
|
File details
Details for the file elephantq-0.1.1-py3-none-any.whl.
File metadata
- Download URL: elephantq-0.1.1-py3-none-any.whl
- Upload date:
- Size: 123.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
67dbc56d9be1f9d7da6c2a8ad7d6a3317bf6928b20de1e6eab1944d5b5c8ba47
|
|
| MD5 |
724f3e17f31cd78e764aed105eed9e80
|
|
| BLAKE2b-256 |
78715ae27b9dd80cffb26bf070aa1fc250b73585ef380e14bd87bb3933fe4dee
|