Skip to main content

Postgres-native background job queue for Rust and Python

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. The Rust runtime handles all queue machinery — polling, LISTEN/NOTIFY wakeups, heartbeating, crash recovery, dispatch — while Python workers run as callbacks via PyO3 on that same runtime, getting Rust-grade queue reliability with Python-native ergonomics.

Features

  • Postgres-only — no Redis, no RabbitMQ. One dependency you already have.
  • Transactional enqueue — insert jobs inside your business transaction. Commit = job exists. Rollback = it doesn't.
  • Two first-class languages — Rust and Python workers on the same queues with identical semantics.
  • SKIP LOCKED dispatch — efficient, contention-free job claiming.
  • Heartbeat + deadline crash recovery — stale jobs rescued automatically.
  • Priority aging — low-priority jobs won't starve.
  • LISTEN/NOTIFY wakeup — sub-10ms pickup latency.
  • OpenTelemetry metrics — built-in counters, histograms, and gauges.

Quick Start (Rust)

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,
}

#[async_trait::async_trait]
impl Worker for SendEmail {
    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?;

// Transactional insert — atomic with your business logic
let mut tx = pool.begin().await?;
create_order(&mut *tx, &order).await?;
awa::insert(&mut *tx, &SendOrderEmail { order_id: order.id }).await?;
tx.commit().await?;

// Start workers
let client = Client::builder(pool)
    .queue("default", QueueConfig::default())
    .register_worker(SendEmail { to: String::new(), subject: String::new() })
    .build()?;
client.start().await?;

Quick Start (Python)

import awa
import asyncio
from dataclasses import dataclass

@dataclass
class SendEmail:
    to: str
    subject: str

client = awa.Client("postgres://localhost/mydb")

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

# Transactional insert — atomic with your business logic
async with await client.transaction() as tx:
    await tx.execute("INSERT INTO orders (id, total) VALUES ($1, $2)", order_id, total)
    await tx.insert(SendEmail(to="alice@example.com", subject="Order confirmed"))
    # Commits on success, rolls back on exception

# Worker
@client.worker(SendEmail, queue="email")
async def handle(job):
    await send_email(job.args.to, job.args.subject)

client.start([("email", 10)])
health = await client.health_check()
assert health.heartbeat_alive

await asyncio.sleep(10)
await client.shutdown()

Note: async with await client.transaction() uses a double-await because transaction() is an async method that returns a context manager. This is inherent to the PyO3 async bridge pattern.

Setup

# Run migrations once (not on every app startup)
awa --database-url $DATABASE_URL migrate
# Or from Python:
# await awa.migrate("postgres://...")

Installation

Rust

[dependencies]
awa = "0.1"

Python

pip install awa-pg

CLI

cargo install awa-cli

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

Architecture

┌────────────────────┐      ┌────────────────────┐
│ Rust producers     │      │ Python producers   │
│ `awa-model` / `awa`│      │ `pip install awa-pg`  │
└─────────┬──────────┘      └─────────┬──────────┘
          │                           │
          └──────────────┬────────────┘
                         ▼
              ┌──────────────────────┐
              │ PostgreSQL `awa.jobs`│
              └──────────┬───────────┘
                         │
        ┌────────────────┼────────────────┐
        │                │                │
        ▼                ▼                ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ Rust runtime  │ │ Rust runtime  │ │ Rust runtime  │
│ + Rust worker │ │ + Python cb   │ │ + Python cb   │
│ `awa-worker`  │ │ via PyO3      │ │ via PyO3      │
└───────────────┘ └───────────────┘ └───────────────┘

All coordination happens through Postgres, and the Rust runtime owns polling, heartbeats, shutdown, and crash recovery for both Rust and Python handlers. Mixed Rust and Python workers coexist on the same queues — jobs inserted from any language are workable by any language.

Workspace

Crate Purpose
awa Facade — re-exports everything
awa-model Types, queries, migrations, admin ops
awa-macros #[derive(JobArgs)] proc macro
awa-worker Runtime: dispatch, heartbeat, maintenance
awa-python PyO3 extension module
awa-testing Test helpers (TestClient)
awa-cli CLI binary

Documentation

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.2.0-cp312-cp312-macosx_11_0_arm64.whl (3.8 MB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

awa_pg-0.2.0-cp312-cp312-macosx_10_12_x86_64.whl (3.9 MB view details)

Uploaded CPython 3.12macOS 10.12+ x86-64

awa_pg-0.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (4.2 MB view details)

Uploaded CPython 3.8manylinux: glibc 2.17+ x86-64

awa_pg-0.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (4.2 MB view details)

Uploaded CPython 3.8manylinux: glibc 2.17+ ARM64

File details

Details for the file awa_pg-0.2.0-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for awa_pg-0.2.0-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 c9089d0e9b605e84b3bc2314275ddd9a978dbdafd9391c03632c0bf810ebc17b
MD5 2bf70de0aa33155fd378af51ee0d5e9b
BLAKE2b-256 dcbd55d76c221928cb33485b198586a1a1052e18acd9e64db8121d2fdeddf307

See more details on using hashes here.

Provenance

The following attestation bundles were made for awa_pg-0.2.0-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.2.0-cp312-cp312-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for awa_pg-0.2.0-cp312-cp312-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 6893dd5ecddb905aa1d4bc6789503261c44090aabb20073a5e321dce55b4d85c
MD5 a04cfe395b27319c88f8b33a7bb43c76
BLAKE2b-256 8f1517c1d0ac3a9bb4635e689ca5d64f47d9c9d2bed9c0952cc45915328187c8

See more details on using hashes here.

Provenance

The following attestation bundles were made for awa_pg-0.2.0-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.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for awa_pg-0.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 7ad01eb9293d3c070a55c29fb665514a1cc20167b9128f93462644c19a37de86
MD5 cf2f0abc3b2cda622d7f63f52721f73f
BLAKE2b-256 5571ecb6013201fee074a4f37c7cc7b78e88b74ae4041dd5563a305823d49a81

See more details on using hashes here.

Provenance

The following attestation bundles were made for awa_pg-0.2.0-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.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for awa_pg-0.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 e093a3b44c5d6122b627f4fbea37965de6094ffe5a2ef68825df6cc668d3d619
MD5 5a6f9f8a3a83c6dec2ff7ffe231fc340
BLAKE2b-256 18a01d69dcbbe98590f7eb53ccfb4a16352699343152dc669f9a4cd3480e6922

See more details on using hashes here.

Provenance

The following attestation bundles were made for awa_pg-0.2.0-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