Awa
Postgres-native background job queue for Rust and Python.
Awa (Māori: river) provides durable, transactional job enqueueing with typed handlers in both Rust and Python. All queue state lives in Postgres — no Redis, no RabbitMQ. The Rust runtime handles polling, heartbeating, crash recovery, and dispatch. Python workers run on that same runtime via PyO3, getting Rust-grade reliability with Python-native ergonomics.

Features
- Postgres-only — one dependency you already have.
- Transactional enqueue — insert jobs inside your business transaction. Commit = visible. Rollback = gone.
- Cancel by unique key — cancel scheduled jobs by their insert-time components (kind + args) without storing job IDs.
- Rust and Python workers — same queues, identical semantics, mixed deployments.
- Crash recovery — heartbeat + hard deadline rescue. Stale jobs recovered automatically.
- Web UI — dashboard, job inspector, queue management, cron controls.
- Structured progress — handlers report percent, message, and checkpoint metadata; persisted across retries.
- Periodic/cron jobs — leader-elected scheduler with timezone support and atomic enqueue.
- Webhook callbacks — park jobs for external completion with optional CEL expression filtering.
- LISTEN/NOTIFY wakeup — sub-10ms pickup latency.
- OpenTelemetry — 20 built-in metrics (counters, histograms, gauges) for Prometheus/Grafana.
- Hot/cold storage — runnable work in a hot table, deferred work in a cold table.
- Rate limiting — per-queue token bucket. Weighted concurrency — global worker pool with per-queue guarantees.
Local benchmarks show ~8k jobs/sec sustained throughput (Rust workers), ~5k jobs/sec (Python workers), and sub-10ms p50 pickup latency. See benchmarking notes for methodology and caveats.
Core concurrency invariants (no duplicate processing after rescue, stale completions rejected, shutdown drain ordering) are checked with TLA+ models covering single and multi-instance deployments.
Getting Started
# 1. Install
# or: cargo add awa # Rust
# 2. Start Postgres and run migrations
# 3. Write a worker and start processing (see examples below)
# 4. Monitor
Language-specific guides:
Python Example
:
:
=
await
await
await
await
Progress tracking — checkpoint and resume on retry:
=
await
Transactional enqueue — atomic with your business logic:
await
await
Sync API for Django/Flask — every async method has a _sync variant:
=
=
See examples/python/ for complete runnable scripts tested in CI.
Rust Example
use ;
use ;
;
// Insert a job (with uniqueness)
insert_with.await?;
// Cancel by unique key (e.g., when the triggering condition is resolved)
cancel_by_unique_key.await?;
// Start workers with a typed lifecycle hook
let client = builder
.queue
.register_worker
.
.build?;
client.start.await?;
Installation
Python
Rust
[]
= "0.4"
CLI
Available via pip (no Rust toolchain needed) or cargo:
# or: cargo install awa-cli
Architecture
┌────────────────┐ ┌────────────────┐
│ Rust producer │ │ Python (pip) │
└───────┬────────┘ └────────┬───────┘
└────────┬───────────┘
▼
┌────────────────────┐
│ PostgreSQL │
│ jobs_hot │
│ scheduled_jobs │
└─────────┬──────────┘
│
┌─────────┼─────────┐
▼ ▼ ▼
┌────────┐┌────────┐┌────────┐
│ Worker ││ Worker ││ Worker │
│ (Rust) ││ (PyO3) ││ (PyO3) │
└────────┘└────────┘└────────┘
All coordination through Postgres. The Rust runtime owns polling, heartbeats, shutdown, and crash recovery for both languages. Mixed Rust and Python workers coexist on the same queues. See architecture overview for full details.
Workspace
| Crate | Purpose |
|---|---|
awa |
Main crate — re-exports awa-model + awa-worker |
awa-model |
Types, queries, migrations, admin ops |
awa-macros |
#[derive(JobArgs)] proc macro |
awa-worker |
Runtime: dispatch, heartbeat, maintenance |
awa-ui |
Web UI (axum API + embedded React frontend) |
awa-cli |
CLI binary (migrations, admin, serve) |
awa-python |
PyO3 extension module (pip install awa-pg) |
awa-testing |
Test helpers (TestClient) |
Documentation
| Doc | Description |
|---|---|
| Rust getting started | From cargo add to a job reaching completed |
| Python getting started | From pip install to a job reaching completed |
| Deployment guide | Docker, Kubernetes, pool sizing, graceful shutdown |
| Migration guide | Fresh installs, upgrades, extracted SQL, rollback strategy |
| Configuration reference | QueueConfig, ClientBuilder, Python start(), env vars |
| Troubleshooting | Stuck running jobs, leader delays, heartbeat timeouts |
| Architecture overview | System design, data flow, state machine, crash recovery |
| Web UI design | API endpoints, pages, component library |
| Benchmarking notes | Methodology, headline numbers, how to run |
| Validation test plan | Full test matrix with 100+ test cases |
| TLA+ correctness models | Formal verification of core invariants |
| Grafana dashboards | Pre-built Prometheus dashboards for monitoring |
- 001: Postgres-only
- 002: BLAKE3 uniqueness
- 003: Heartbeat + deadline hybrid
- 004: PyO3 async bridge
- 005: Priority aging
- 006: AwaTransaction as narrow SQL surface
- 007: Periodic cron jobs
- 008: COPY batch ingestion
- 009: Python sync support
- 010: Per-queue rate limiting
- 011: Weighted concurrency
- 012: Split hot and deferred job storage
- 013: Durable run leases and guarded finalization
- 014: Structured progress and metadata
- 015: Builder-side post-commit lifecycle hooks
License
MIT OR Apache-2.0