Skip to main content

Postgres-native background job queue — Python SDK with async/sync workers, transactional enqueue, progress tracking, and web UI

Project description

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.

AWA Web UI — Dashboard (dark mode)

Features

  • Postgres-only — one dependency you already have.
  • Transactional enqueue — insert jobs inside your business transaction. Commit = visible. Rollback = gone.
  • 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
pip install awa-pg awa-cli     # Python
# or: cargo add awa             # Rust

# 2. Start Postgres and run migrations
awa --database-url $DATABASE_URL migrate

# 3. Write a worker and start processing (see examples below)

# 4. Monitor
awa --database-url $DATABASE_URL serve   # → http://127.0.0.1:3000

Python Example

import awa
import asyncio
from dataclasses import dataclass

@dataclass
class SendEmail:
    to: str
    subject: str

async def main():
    client = awa.Client("postgres://localhost/mydb")
    await client.migrate()

    @client.worker(SendEmail, queue="email")
    async def handle_email(job):
        print(f"Sending to {job.args.to}: {job.args.subject}")

    await client.insert(SendEmail(to="alice@example.com", subject="Welcome"))

    client.start([("email", 2)])
    await asyncio.sleep(1)
    await client.shutdown()

asyncio.run(main())

Progress tracking — checkpoint and resume on retry:

@client.worker(BatchImport, queue="etl")
async def handle_import(job):
    last_id = (job.progress or {}).get("metadata", {}).get("last_id", 0)
    for item in fetch_items(after=last_id):
        process(item)
        job.set_progress(50, "halfway")
        job.update_metadata({"last_id": item.id})
    await job.flush_progress()

Transactional enqueue — atomic with your business logic:

async with await client.transaction() as tx:
    await tx.execute("INSERT INTO orders (id) VALUES ($1)", order_id)
    await tx.insert(SendEmail(to="alice@example.com", subject="Order confirmed"))

Sync API for Django/Flask — every async method has a _sync variant:

client = awa.Client("postgres://localhost/mydb")
client.migrate_sync()
job = client.insert_sync(SendEmail(to="bob@example.com", subject="Hello"))

See awa-python/examples/ for complete runnable scripts tested in CI.

Rust Example

use awa::{Client, QueueConfig, JobArgs, JobResult, JobError, JobContext, JobRow, Worker};
use serde::{Serialize, Deserialize};

#[derive(Debug, Serialize, Deserialize, JobArgs)]
struct SendEmail {
    to: String,
    subject: String,
}

struct SendEmailWorker;

#[async_trait::async_trait]
impl Worker for SendEmailWorker {
    fn kind(&self) -> &'static str { "send_email" }

    async fn perform(&self, job: &JobRow, ctx: &JobContext) -> Result<JobResult, JobError> {
        let args: SendEmail = serde_json::from_value(job.args.clone())
            .map_err(|e| JobError::terminal(e.to_string()))?;
        send_email(&args.to, &args.subject).await
            .map_err(JobError::retryable)?;
        Ok(JobResult::Completed)
    }
}

// Insert a job
awa::insert(&pool, &SendEmail { to: "alice@example.com".into(), subject: "Welcome".into() }).await?;

// Start workers
let client = Client::builder(pool)
    .queue("default", QueueConfig::default())
    .register_worker(SendEmailWorker)
    .build()?;
client.start().await?;

Installation

Python

pip install awa-pg       # SDK: insert, worker, admin, progress
pip install awa-cli      # CLI: migrations, queue admin, web UI

Rust

[dependencies]
awa = "0.2"

CLI

Available via pip (no Rust toolchain needed) or cargo:

pip install awa-cli
# or: cargo install awa-cli

awa --database-url $DATABASE_URL migrate
awa --database-url $DATABASE_URL serve
awa --database-url $DATABASE_URL queue stats
awa --database-url $DATABASE_URL job list --state failed

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
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
Architecture Decision Records (ADRs)

License

MIT OR Apache-2.0

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 Distributions

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

awa_pg-0.3.0a3-cp312-cp312-macosx_11_0_arm64.whl (5.3 MB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

awa_pg-0.3.0a3-cp312-cp312-macosx_10_12_x86_64.whl (5.5 MB view details)

Uploaded CPython 3.12macOS 10.12+ x86-64

awa_pg-0.3.0a3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (5.9 MB view details)

Uploaded CPython 3.8manylinux: glibc 2.17+ x86-64

awa_pg-0.3.0a3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (6.0 MB view details)

Uploaded CPython 3.8manylinux: glibc 2.17+ ARM64

File details

Details for the file awa_pg-0.3.0a3-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for awa_pg-0.3.0a3-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 152669a942e17e51f6a1465ffaee9c44e700ae60613ef3580342e85684cae665
MD5 2d25b67b0ba9b8fe900b910b44306e09
BLAKE2b-256 8a2ca6fc79a002b10e255bafacb6f43dc46d7162c662ff487dba06d0cfc9a47a

See more details on using hashes here.

Provenance

The following attestation bundles were made for awa_pg-0.3.0a3-cp312-cp312-macosx_11_0_arm64.whl:

Publisher: release.yml on hardbyte/awa

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file awa_pg-0.3.0a3-cp312-cp312-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for awa_pg-0.3.0a3-cp312-cp312-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 563ee40346e9bb593bfabab8066f2902e633a89873315120b4c3fb4e86df2400
MD5 9127154fed69d13fa054a80e8283c571
BLAKE2b-256 d37a571592ed632369adc4d8692038f76ecb2412c1cb1e6a7cb3218433e80878

See more details on using hashes here.

Provenance

The following attestation bundles were made for awa_pg-0.3.0a3-cp312-cp312-macosx_10_12_x86_64.whl:

Publisher: release.yml on hardbyte/awa

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file awa_pg-0.3.0a3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for awa_pg-0.3.0a3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 a9238acc62e7bc80c31a8b7014a803295c0ebc803e7d51f96bb09a849f8a56c5
MD5 226c6af5e9a7fb69c3dc593c50741b70
BLAKE2b-256 2eca636c4973ef4dc1a6cd3f59d4f21f8ed1ebcf7dc71fd3083323fb3a650692

See more details on using hashes here.

Provenance

The following attestation bundles were made for awa_pg-0.3.0a3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: release.yml on hardbyte/awa

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file awa_pg-0.3.0a3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for awa_pg-0.3.0a3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 ff3ff45d26aee9276a43802bd44bcf1cecc0d41c5bb6ed64911d0eb90fe697ba
MD5 856e5ed91e26e4c192d47eb07557ea5f
BLAKE2b-256 a236000cdea7a379057a07e97cbb389bcb2c7f621b520a730b2806fc6db0b423

See more details on using hashes here.

Provenance

The following attestation bundles were made for awa_pg-0.3.0a3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: release.yml on hardbyte/awa

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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