Documentation
Examples
From your first background job to a full Axum web app. Each example is self-contained and runnable.
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(())
}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(())
}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;
}
}
}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(())
}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;
}
}
}