Background jobs for Rust
A Rust port of BullMQ. It uses the same Lua scripts and Redis data structures as the Node.js and Elixir libraries, so they can all work on the same queues.
cargo add bullmq
Rust 1.85+ (edition 2021) · tokio · Redis 6.2+ (or Valkey/Dragonfly)
Your first queue and worker
use bullmq::{Queue, QueueOptions, JobOptions};
let queue = Queue::new("Paint", QueueOptions::default()).await?;
queue
.add(
"cars",
serde_json::json!({"color": "blue"}),
Some(JobOptions {
delay: Some(30_000),
..Default::default()
}),
)
.await?;use bullmq::{Worker, WorkerOptions, Job};
use std::sync::Arc;
let worker = Worker::new(
"Paint",
Arc::new(|job: Job, _token| {
Box::pin(async move {
if job.name() == "cars" {
paint_car(job.data()["color"].as_str().unwrap()).await;
}
Ok(serde_json::json!({"painted": true}))
})
}),
WorkerOptions {
concurrency: 100,
..Default::default()
},
)
.await?;More Rust examples
Common BullMQ features, written in Rust.
Global events
use bullmq::{QueueEvent, QueueEvents, QueueEventsOptions};
let events = QueueEvents::new(
"Paint",
QueueEventsOptions::default(),
)
.await?;
while let Some(entry) = events.next_event().await {
match entry.event {
QueueEvent::Completed { job_id, .. } => {
println!("Job {job_id} completed");
}
QueueEvent::Failed { job_id, failed_reason, .. } => {
println!("Job {job_id} failed: {failed_reason}");
}
_ => {}
}
}Repeatable jobs
use bullmq::job_scheduler::RepeatOptions;
use bullmq::{Queue, QueueOptions};
let queue = Queue::new("Paint", QueueOptions::default()).await?;
// Repeat job once every day at 3:15 (am)
queue
.upsert_job_scheduler(
"daily-submarine",
RepeatOptions {
pattern: Some("0 15 3 * * *".into()),
..Default::default()
},
Some("submarine"),
Some(serde_json::json!({"color": "yellow"})),
None,
)
.await?;Rate limiting
use bullmq::{Job, RateLimiterOptions, Worker, WorkerOptions};
use std::sync::Arc;
let worker = Worker::new(
"Paint",
Arc::new(|job: Job, _token| {
Box::pin(async move {
paint_car(&job).await;
Ok(serde_json::Value::Null)
})
}),
WorkerOptions {
limiter: Some(RateLimiterOptions {
max: 10,
duration: 1000,
}),
..Default::default()
},
)
.await?;Retries & backoff
use bullmq::{Queue, QueueOptions, JobOptions};
use bullmq::types::BackoffStrategy;
let queue = Queue::new("Paint", QueueOptions::default()).await?;
queue
.add(
"car",
serde_json::json!({"color": "pink"}),
Some(JobOptions {
attempts: Some(3),
backoff: Some(BackoffStrategy::Exponential(1000)),
..Default::default()
}),
)
.await?;Flows
use bullmq::{FlowJob, FlowProducer, FlowProducerOptions};
let flow = FlowProducer::new(FlowProducerOptions::default()).await?;
flow.add(FlowJob {
name: "Renovate".into(),
queue_name: "cars".into(),
data: serde_json::json!({}),
opts: None,
prefix: None,
children: Some(
["paint", "engine", "wheels"]
.into_iter()
.map(|name| FlowJob {
name: name.into(),
queue_name: "steps".into(),
data: serde_json::json!({}),
opts: None,
prefix: None,
children: None,
})
.collect(),
),
})
.await?;Using BullMQ with Rust
Built on tokio
Workers are async and support configurable concurrency, stalled job detection and lock renewal.
Metrics
Collect time-series metrics for your queues and export them in Prometheus format.
Bindings
The API is trait-based and designed to make bindings to Go, C#, Python and other languages easy to write.
One queue, any language
Keep adding jobs from your Node.js services and process the CPU-heavy ones in Rust workers. The queue does not change.
What's available in Rust
- Add jobs to queues Supported
- Process jobs (workers) Supported
- Delayed jobs Supported
- Repeatable / scheduled jobs Supported
- Job priorities Supported
- Rate limiting Supported
- Retries & backoff Supported
- Flows (parent / child) Supported
- Job events Supported
- Redis backend Supported
- PostgreSQL backend Coming soon
- BullMQ Pro Coming soon
BullMQ Pro for Rust Coming soon
BullMQ Pro adds groups, observables and batches to the open source library. It is available for Node.js and Bun today, and support for Rust is on the way.