use processor::state::{DistributedLock, RedisLock};
use std::time::Duration;
use tokio::time::sleep;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
tracing_subscriber::fmt()
.with_max_level(tracing::Level::INFO)
.init();
println!("=== Distributed Lock Demo ===\n");
let instance_id = uuid::Uuid::new_v4().to_string()[..8].to_string();
println!("Instance ID: {}\n", instance_id);
println!("--- Demo 1: Basic Lock Acquisition ---");
let lock = RedisLock::new("redis://localhost:6379", "demo:basic_lock").await?;
println!("Attempting to acquire lock...");
let acquired = lock.try_lock(Duration::from_secs(30)).await?;
if acquired {
println!("✓ Lock acquired!");
println!(" Holding lock for 2 seconds...");
sleep(Duration::from_secs(2)).await;
println!(" Releasing lock...");
lock.unlock().await?;
println!("✓ Lock released\n");
} else {
println!("✗ Failed to acquire lock (already held by another instance)\n");
}
println!("--- Demo 2: Lock Expiration ---");
let lock_expire = RedisLock::new("redis://localhost:6379", "demo:expire_lock").await?;
println!("Acquiring lock with 3-second TTL...");
let acquired = lock_expire.try_lock(Duration::from_secs(3)).await?;
if acquired {
println!("✓ Lock acquired");
println!(" Waiting 4 seconds for expiration...");
sleep(Duration::from_secs(4)).await;
let lock_expire2 = RedisLock::new("redis://localhost:6379", "demo:expire_lock").await?;
let acquired2 = lock_expire2.try_lock(Duration::from_secs(10)).await?;
if acquired2 {
println!("✓ Acquired expired lock (automatic cleanup worked)");
lock_expire2.unlock().await?;
}
}
println!();
println!("--- Demo 3: Lock with Closure (RAII Pattern) ---");
let lock_raii = RedisLock::new("redis://localhost:6379", "demo:raii_lock").await?;
println!("Executing critical section with automatic lock management...");
let result = lock_raii
.with_lock(Duration::from_secs(30), || async {
println!(" → Inside critical section");
println!(" → Performing work...");
sleep(Duration::from_millis(500)).await;
println!(" → Work complete");
Ok::<i32, anyhow::Error>(42)
})
.await?;
println!("✓ Critical section completed with result: {}", result);
println!("✓ Lock automatically released\n");
println!("--- Demo 4: Leader Election ---");
let leader_lock = RedisLock::new("redis://localhost:6379", "demo:leader").await?;
println!("Attempting leader election...");
let is_leader = leader_lock.try_lock(Duration::from_secs(30)).await?;
if is_leader {
println!("✓ This instance is the LEADER");
println!(" Leader tasks:");
println!(" - Coordinating worker instances");
println!(" - Managing distributed tasks");
println!(" - Handling failover");
for i in 1..=5 {
println!(" [Leader] Heartbeat {}/5", i);
sleep(Duration::from_millis(500)).await;
}
println!(" Stepping down as leader...");
leader_lock.unlock().await?;
println!("✓ Leadership released\n");
} else {
println!("✗ This instance is a FOLLOWER");
println!(" Follower tasks:");
println!(" - Waiting for leader commands");
println!(" - Processing delegated work");
println!(" - Ready to become leader if needed\n");
}
println!("--- Demo 5: Lock Renewal ---");
let renew_lock = RedisLock::new("redis://localhost:6379", "demo:renew_lock").await?;
println!("Acquiring lock for long-running task...");
let acquired = renew_lock.try_lock(Duration::from_secs(5)).await?;
if acquired {
println!("✓ Lock acquired with 5-second TTL");
let renew_lock_clone = RedisLock::new("redis://localhost:6379", "demo:renew_lock").await?;
let renewal_handle = tokio::spawn(async move {
for i in 1..=3 {
sleep(Duration::from_secs(3)).await;
println!(" [Renewal] Extending lock TTL (attempt {})", i);
if let Err(e) = renew_lock_clone.renew(Duration::from_secs(5)).await {
eprintln!(" [Renewal] Failed to extend: {}", e);
break;
}
}
});
println!(" Performing long-running task (10 seconds)...");
for i in 1..=10 {
println!(" [Work] Progress: {}0%", i);
sleep(Duration::from_secs(1)).await;
}
renewal_handle.await?;
renew_lock.unlock().await?;
println!("✓ Task complete, lock released\n");
}
println!("--- Demo 6: Coordinated Work Distribution ---");
let tasks = vec!["task_1", "task_2", "task_3", "task_4", "task_5"];
for task_id in tasks {
let lock_key = format!("demo:task:{}", task_id);
let task_lock = RedisLock::new("redis://localhost:6379", &lock_key).await?;
println!("Attempting to claim {}...", task_id);
if task_lock.try_lock(Duration::from_secs(10)).await? {
println!(" ✓ Claimed {} (instance: {})", task_id, instance_id);
println!(" Processing...");
sleep(Duration::from_millis(300)).await;
println!(" Complete!");
task_lock.unlock().await?;
} else {
println!(" ✗ {} already claimed by another instance", task_id);
}
}
println!();
println!("--- Demo 7: Multiple Resource Locks ---");
let resource_a = RedisLock::new("redis://localhost:6379", "demo:resource:a").await?;
let resource_b = RedisLock::new("redis://localhost:6379", "demo:resource:b").await?;
println!("Acquiring multiple resources atomically...");
let lock_a = resource_a.try_lock(Duration::from_secs(10)).await?;
if lock_a {
println!(" ✓ Acquired resource A");
let lock_b = resource_b.try_lock(Duration::from_secs(10)).await?;
if lock_b {
println!(" ✓ Acquired resource B");
println!(" → Both resources locked, performing atomic operation");
sleep(Duration::from_millis(500)).await;
println!(" ✓ Operation complete");
resource_b.unlock().await?;
println!(" ✓ Released resource B");
} else {
println!(" ✗ Could not acquire resource B");
}
resource_a.unlock().await?;
println!(" ✓ Released resource A");
} else {
println!(" ✗ Could not acquire resource A");
}
println!();
println!("--- Demo 8: Lock Monitoring ---");
let monitor_lock = RedisLock::new("redis://localhost:6379", "demo:monitor").await?;
if monitor_lock.try_lock(Duration::from_secs(30)).await? {
println!("✓ Lock acquired");
println!(" Checking lock status...");
let is_locked = monitor_lock.is_locked().await?;
println!(" Locked: {}", is_locked);
if let Some(holder) = monitor_lock.get_holder().await? {
println!(" Holder: {}", holder);
}
if let Some(ttl) = monitor_lock.get_ttl().await? {
println!(" TTL: {:?}", ttl);
}
monitor_lock.unlock().await?;
println!(" ✓ Lock released");
let is_locked_after = monitor_lock.is_locked().await?;
println!(" Locked after release: {}", is_locked_after);
}
println!();
println!("--- Demo 9: Concurrent Lock Attempts ---");
let lock_name = "demo:concurrent";
let mut handles = vec![];
println!("Spawning 5 concurrent tasks competing for the same lock...");
for i in 0..5 {
let instance = format!("worker-{}", i);
let handle = tokio::spawn(async move {
let lock = RedisLock::new("redis://localhost:6379", lock_name).await?;
if lock.try_lock(Duration::from_secs(10)).await? {
println!(" ✓ {} acquired lock", instance);
sleep(Duration::from_millis(500)).await;
lock.unlock().await?;
println!(" ✓ {} released lock", instance);
Ok::<bool, anyhow::Error>(true)
} else {
println!(" ✗ {} failed to acquire lock", instance);
Ok(false)
}
});
handles.push(handle);
}
let mut successful = 0;
for handle in handles {
if handle.await?? {
successful += 1;
}
}
println!("\n Results: {} successful, {} failed\n", successful, 5 - successful);
println!("--- Demo 10: Graceful Shutdown ---");
let shutdown_lock = RedisLock::new("redis://localhost:6379", "demo:shutdown").await?;
if shutdown_lock.try_lock(Duration::from_secs(30)).await? {
println!("✓ Acquired shutdown lock");
println!(" Performing graceful shutdown sequence:");
println!(" 1. Stopping new work");
sleep(Duration::from_millis(200)).await;
println!(" 2. Completing in-flight tasks");
sleep(Duration::from_millis(200)).await;
println!(" 3. Flushing buffers");
sleep(Duration::from_millis(200)).await;
println!(" 4. Releasing resources");
sleep(Duration::from_millis(200)).await;
shutdown_lock.unlock().await?;
println!(" ✓ Shutdown complete, lock released");
}
println!();
println!("=== Demo Complete ===");
println!("\nTo see multi-instance behavior:");
println!(" 1. Run this example in multiple terminals");
println!(" 2. Observe leader election and lock contention");
println!(" 3. See coordinated work distribution");
Ok(())
}