Crate rdlock

Source
Expand description

rdlock: A library for distributed redis locks written in rust.

Before using, make sure your redis instance has notify-keyspace-events enabled with KA flags.

§Example with a basic lock

Please note, this should never be used for locks between multiple threads/tasks in the same process, we have blocking and non-blocking primitives for those situations that are already available and well-optimized, so please use those when possible.

This library is useful when we need to synchronize across multiple processes with a local redis server, or, more importantly, across multiple machines, e.g. pods inside a cluster.

In this example, we could consider h1 machine A and h2 machine B, connecting to a “remote” redis instance.

use rdlock::RdLockConnectionManager;
use std::time::Duration;

async fn do_work(manager: RdLockConnectionManager) {
   println!("Started thread");
   let mut basic_lock = manager.new_basic_lock("my_lock", 3600);

   basic_lock.lock().await.unwrap();
   println!("Acquired lock");

   // Do stuff
   tokio::time::sleep(Duration::from_secs(5)).await;

   println!("Releasing lock");
   basic_lock.release().await.unwrap();

}

#[tokio::main]
pub async fn main() {
   let manager = RdLockConnectionManager::new("redis://localhost").await.unwrap();

   // Both machines will use the same `lock_id`, so they will target the same lock.

   // This is clone safe
   let manager_clone = manager.clone();
   let h1 = tokio::spawn(async move {
       do_work(manager_clone).await
   });

   let manager_clone = manager.clone();
   let h2 = tokio::spawn(async move {
       do_work(manager_clone).await
   });

   let _ = h1.await;
   let _ = h2.await;
}

You should always get something like this:

Started thread
Started thread
Acquired lock
Releasing lock
Acquired lock
Releasing lock

And never something like this:

Started thread
Started thread
Acquired lock
Acquired lock
Releasing lock
Releasing lock

§Lock ID

All unique locks should use unique ids. This means that you should use the same lock_id across instances when targeting the same lock, but a different lock_id when you want to target a different lock.

// Machine A
let machine_a_manager = RdLockConnectionManager::new("<redis remote url>").await.unwrap();

// Targets the same lock as `machine_b_dog_lock`
let machine_a_dog_lock = machine_a_manager.new_basic_lock("dog", 3600);
// Targets the same lock as `machine_b_cat_lock`
let machine_a_cat_lock = machine_a_manager.new_basic_lock("cat", 3600);


// Machine B
let machine_b_manager = RdLockConnectionManager::new("<redis remote url>").await.unwrap();

// Targets the same lock as `machine_a_dog_lock`
let machine_b_dog_lock = machine_b_manager.new_basic_lock("dog", 3600);
// Targets the same lock as `machine_a_cat_lock`
let machine_b_cat_lock = machine_b_manager.new_basic_lock("cat", 3600);

Modules§

errors
lock
utils

Structs§

RdLockConnectionManager
The RdLockConnectionManager is used to connect to a redis instance and initialize locks.