use durare::{
DurableContext, DurableEngine, InMemoryProvider, RateLimiter, Result, WorkflowOptions,
WorkflowQueue,
};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::time::Duration;
static IN_FLIGHT: AtomicUsize = AtomicUsize::new(0);
static PEAK: AtomicUsize = AtomicUsize::new(0);
#[durare::step]
async fn resize(ctx: &DurableContext, image: String) -> Result<u64> {
tokio::time::sleep(Duration::from_millis(60)).await;
Ok(image.len() as u64 * 1024)
}
#[durare::workflow]
async fn make_thumbnail(ctx: DurableContext, image: String) -> Result<u64> {
let running = IN_FLIGHT.fetch_add(1, Ordering::SeqCst) + 1;
PEAK.fetch_max(running, Ordering::SeqCst);
let bytes = resize(&ctx, image.clone()).await?;
println!(" >> processed {image} -> {bytes} bytes ({running} in flight)");
IN_FLIGHT.fetch_sub(1, Ordering::SeqCst);
Ok(bytes)
}
#[tokio::main]
async fn main() -> Result<()> {
let mut engine = DurableEngine::new(Arc::new(InMemoryProvider::new())).await?;
engine.register_queue(
WorkflowQueue::new("thumbnails")
.worker_concurrency(3)
.rate_limiter(RateLimiter {
limit: 1000,
period: Duration::from_secs(1),
}),
);
engine.launch().await?;
let images = [
"cat", "dog", "bird", "fish", "frog", "newt", "mole", "wolf", "lynx",
];
println!("[enqueue] {} images onto a 3-worker queue", images.len());
let mut handles = Vec::new();
for name in images {
handles.push(
engine
.start::<_, u64>(
"make_thumbnail",
name.to_string(),
WorkflowOptions::with_id(format!("thumb-{name}")).queue("thumbnails"),
)
.await?,
);
}
let mut total = 0u64;
for h in handles {
total += h.result().await?;
}
println!("[done] {total} bytes across all thumbnails");
println!(
"[peak] at most {} jobs ran at once (worker_concurrency was 3)",
PEAK.load(Ordering::SeqCst)
);
engine.shutdown(Duration::from_secs(1)).await?;
Ok(())
}