Documentation

Examples

From your first background job to a full Axum web app. Each example is self-contained and runnable.

Beginner

Basic Push / Pull / Ack

The simplest possible RustQueue usage. Push a job, pull it, acknowledge it. Uses an in-memory backend — no files, no setup.

use rustqueue::RustQueue;
use serde_json::json!;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let rq = RustQueue::memory().build()?;

    // Push a job onto the "emails" queue
    let id = rq.push("emails", "send-welcome",
        json!({"to": "user@example.com", "template": "welcome"}),
        None,
    ).await?;
    println!("Pushed job: {id}");

    // Pull one job from the queue
    let jobs = rq.pull("emails", 1).await?;
    println!("Processing: {} (data: {})", jobs[0].name, jobs[0].data);

    // Acknowledge completion
    rq.ack(jobs[0].id, None).await?;
    println!("Done!");
    Ok(())
}
cargo run --example basic
Beginner

Persistent Queue

Jobs survive process restarts. Run this example twice — the second run finds the job pushed in the first run still waiting in the queue.

use rustqueue::RustQueue;
use serde_json::json!;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let rq = RustQueue::redb("/tmp/rustqueue-example.db")?.build()?;

    // Check if there are jobs from a previous run
    let existing = rq.pull("tasks", 1).await?;
    if !existing.is_empty() {
        println!("Found job from previous run: {}", existing[0].name);
        rq.ack(existing[0].id, None).await?;
        return Ok(());
    }

    // No existing jobs — push one and exit
    let id = rq.push("tasks", "generate-report",
        json!({"report": "monthly"}), None).await?;
    println!("Pushed job {id}. Run again to see it survive the restart.");
    Ok(())
}
cargo run --example persistent
Intermediate

Worker Loop

A long-running worker that polls the queue and processes jobs as they arrive. The standard pattern for background job processing.

use rustqueue::RustQueue;
use std::time::Duration;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let rq = RustQueue::redb("/tmp/rustqueue-worker.db")?.build()?;
    println!("Worker started. Waiting for jobs...");

    loop {
        let jobs = rq.pull("emails", 5).await?;
        for job in &jobs {
            println!("[{}] Processing: {}", job.queue, job.name);
            tokio::time::sleep(Duration::from_millis(100)).await;
            rq.ack(job.id, None).await?;
        }
        if jobs.is_empty() {
            tokio::time::sleep(Duration::from_millis(500)).await;
        }
    }
}
cargo run --example worker
Intermediate

Axum Web App with Background Jobs

A full Axum web application with a background job queue. The RqState extractor provides RustQueue to any handler. A spawned worker task processes jobs in the background.

use axum::routing::{get, post};
use axum::{Json, Router};
use rustqueue::axum_integration::RqState;
use rustqueue::RustQueue;
use serde_json::json!;
use std::sync::Arc;

async fn send_email(rq: RqState, Json(body): Json<serde_json::Value>)
    -> Json<serde_json::Value>
{
    let to = body["to"].as_str().unwrap_or("unknown");
    let id = rq.push("emails", "send-welcome",
        json!({"to": to}), None).await.unwrap();
    Json(json!({"queued": true, "job_id": id.to_string()}))
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let rq = Arc::new(RustQueue::redb("/tmp/rq-axum.db")?.build()?);
    let app = Router::new()
        .route("/send-email", post(send_email))
        .with_state(rq);
    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await?;
    axum::serve(listener, app).await?;
    Ok(())
}
cargo run --example axum_background_jobs
Advanced

Email Notifications with Priority & Retry

A realistic email notification service with priority queues, simulated SMTP failures, and crash-safe persistence. Password resets jump ahead of welcome emails. Failed sends retry with exponential backoff. Kill the process mid-send and restart — emails resume where they left off. Read the tutorial →

use rustqueue::{JobOptions, RustQueue};
use rustqueue::axum_integration::RqState;

// Password resets get higher priority and more retries
async fn reset_password(rq: RqState, Json(body): Json<serde_json::Value>)
    -> Json<serde_json::Value>
{
    let id = rq.push("emails", "password-reset",
        json!({ "to": email, "subject": "Reset your password" }),
        Some(JobOptions {
            priority: Some(10),      // Jump ahead of welcome emails
            max_attempts: Some(5),   // More retries for critical emails
            ..Default::default()
        }),
    ).await.unwrap();
    Json(json!({"queued": true}))
}

// Worker: pull, send, ack or fail (auto-retries on failure)
async fn email_worker(rq: Arc<RustQueue>) {
    loop {
        let jobs = rq.pull("emails", 5).await.unwrap();
        for job in &jobs {
            match send_email(&job.data).await {
                Ok(()) => rq.ack(job.id, None).await.unwrap(),
                Err(e) => rq.fail(job.id, &e).await.unwrap(),
            }
        }
        if jobs.is_empty() {
            tokio::time::sleep(Duration::from_millis(200)).await;
        }
    }
}
cargo run --example email_notifications