async-redis-lock 0.0.5

A simple and easy-to-use asynchronous redis distributed lock implementation based on tokio and redis-rs.
Documentation

async-redis-lock

Crates.io docs

A simple and easy-to-use asynchronous redis distributed lock implementation based on tokio and redis-rs.

Key Features

  • Auto Extension - Automatically extends lock lifetime in background until released
  • 🔒 Passive Release - Lock automatically releases when lifetime expires after process crash
  • 🎯 Drop Support - Supports both implicit release via drop and explicit release via method call

Quick Start

Installation

[dependencies]
async-redis-lock = "0.0.1"

Basic Usage

use async_redis_lock::Locker;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Create locker
    let mut locker = Locker::from_redis_url("redis://127.0.0.1:6379/0").await?;

    // Acquire lock
    let lock = locker.acquire("lock_key").await?;

    // At this point:
    // 1. Lock is held
    // 2. Background task automatically extends lock TTL
    // 3. Safe to perform critical operations
    // ...    
    
    // Release lock explicitly
    // Alternative: drop(lock) for implicit release
    lock.release()?;

    Ok(())
}

Automatic Release

use async_redis_lock::Locker;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let mut locker = Locker::from_redis_url("redis://127.0.0.1:6379/0").await?;

    // Use block scope to control lock lifetime
    {
        // Acquire lock and store in _lock variable
        // The _ prefix indicates we only care about its Drop behavior
        let _lock = locker.acquire("lock_key").await?;
        // Perform operations that require locking
        // ...
        // Lock will be automatically released when block ends
        // Thanks to Rust's Drop trait implementation
    }

    Ok(())
}

Advanced Configuration

use async_redis_lock::Locker;
use async_redis_lock::options::Options;
use std::time::Duration;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let mut locker = Locker::from_redis_url("redis://127.0.0.1:6379/0").await?;
    
    // Build a custom lock options
    let opts = Options::new()
        // Set interval between acquisition attempts
        // Default: 100ms
        .retry(Duration::from_millis(100))
        // Set maximum time to attempt acquisition
        // Default: Some(1s)
        // Note: none means retry indefinitely
        .timeout(Some(Duration::from_secs(1)))
        // Set lock time-to-live before auto-release
        // Default: 3s
        .ttl(Duration::from_secs(3))
        // Set lock auto-extend interval
        // Default: 1s
        // Recommend: lifetime/3
        .extend(Duration::from_secs(1));
    
     // Acquire lock with the custom options
    let _lock = locker.acquire_with_options(&opts, "lock_key").await?;

    // Perform operations that require locking
    // ...
    
    Ok(())
}

Important Notes

  1. Don't ignore the return value of acquire method, or the lock will release immediately
  2. extend_interval must be less than lifetime to prevent unintended release
  3. Lock implements Drop trait and will auto-release when out of scope

License

MIT

Contributions and suggestions are welcome!