Giter VIP home page Giter VIP logo

rslock's Introduction

rslock - Redlock for Redis in Rust

Crates.io Docs badge

This is an implementation of Redlock, the distributed locking mechanism built on top of Redis.

Features

  • Lock extending
  • Async runtime support (async-std and tokio)
  • Async redis

Install

cargo add rslock

Note

The default feature of this crate will provide async-std. You may optionally use tokio by supplying the tokio-comp feature flag when installing, but tokio has limitations that will not grant access to some parts of the API (read more here).

Build

cargo build --release

Usage

use std::time::Duration;

use rslock::LockManager;

#[tokio::main]
async fn main() {
    let rl = LockManager::new(vec![
        "redis://127.0.0.1:6380/",
        "redis://127.0.0.1:6381/",
        "redis://127.0.0.1:6382/",
    ]);

    let lock;
    loop {
        // Create the lock
        if let Ok(l) = rl
            .lock("mutex".as_bytes(), Duration::from_millis(1000))
            .await
        {
            lock = l;
            break;
        }
    }

    // Extend the lock
    match rl.extend(&lock, Duration::from_millis(1000)).await {
        Ok(_) => println!("lock extended!"),
        Err(_) => println!("lock couldn't be extended"),
    }

    // Unlock the lock
    rl.unlock(&lock).await;
}

Extending Locks

Extending a lock effectively renews its duration instead of adding extra time to it. For instance, if a 1000ms lock is extended by 1000ms after 500ms pass, it will only last for a total of 1500ms, not 2000ms. This approach is consistent with the Node.js Redlock implementation. See the extend script.

Tests

Run tests with:

cargo test

Contribute

If you find bugs or want to help otherwise, please open an issue.

License

BSD. See LICENSE.

rslock's People

Contributors

aig787 avatar badboy avatar boxdot avatar csm-kb avatar dependabot[bot] avatar github-actions[bot] avatar hexcowboy avatar hgzimmerman avatar homu avatar leoven avatar rsecob avatar serprex avatar zyddnys avatar zzhengzhuo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

rslock's Issues

Lock Ownership Model

Use Case

I'm trying to do is use the LockManager, to create a lock, and pass it to a tokio channel.

Something like

let entry: T;
let lockManager = LockManager::new();
let lock = lockManager.lock();
channel.send( (entry, lock) );

Issue

However rust is complaining that the lockManager will go out of scope. So I tried to send both the lockManager and the lock through the channel.

Changing the logic to

let entry: T;
let lockManager = Arc::new(LockManager::new());
let lock: Lock<'_> = lockManager.lock(..., ...);
channel.send( (entry, lock) );

does not work.

Proposed Change

I think the developer experience could be improved if you did something like this:

pub struct Lock<'a> {
    /// The resource to lock. Will be used as the key in Redis.
    pub resource: Vec<u8>,
    /// The value for this lock.
    pub val: Vec<u8>,
    /// Time the lock is still valid.
    /// Should only be slightly smaller than the requested TTL.
    pub validity_time: usize,
    /// Used to limit the lifetime of a lock to its lock manager.
    pub lock_manager: Arc<LockManagerInner>,
}

pub struct LockManagerInner { 
...
}

pub struct LockManager { 
   pub lock_manager: Arc<LockManagerInner>
}

This would allow a channel responsible for creating locks, a channel for doing other stuff, and a channel for closing locks to be represented clearly without having to worry about lifetimes.

This is the pattern that the mongo driver for rust uses & it moves the complexity from the user to the crate.

Would you welcome a PR for this change?

LockManager.lock() panics with a small TTL, when retrying

We have a TTL set to five seconds. Calling LockManager.lock() with even 1 second of retries, results in panic.

Here is a minimal example that illustrates the panic and its conditions. The failing code is in the private LockManager.exec_or_retry(), so I have just copied the relevant lines and values to the Playground.

A better behavior would be returning an error with an explanation.
Happy to contribute, if I can get guidance from crate owners/maintainers. ๐Ÿ™

RSLock: Questions regarding 1) Setup Requirements and 2) safety for Multithread Applications & Arc<>

My questions are as follows:

  1. What are the setup requirements for rslock? Do I need to be running a pre-existing redis instance?
  2. Is the rslock library safe to use in a Multithreaded context? More specifically, I am using the rocket library in rust trying to store the RSLock Manager in an Arc so I can pass it as State to multiple requests. However, the lock keeps failing to acquire.

Any help would be deeply appreciated.

Feature request: allow rslock functionality on an already established Redis connection

I started implementing similar functionality to this library yesterday and then discovered rslock. Since I'm already using Redis in my app for other things, it feels like I can't really use rslock since it has different assumptions about how it should be setup (i.e. through LockManager::new()). I think you could make rslock more flexible for others if you put most of the functionality in a trait that could be implemented for an existing Redis connection object. I might take a stab at this in the near future and submit a PR.

TTL as std::time::Duration

Hi! I was thinking about refactoring ttl parameters to be of type std::time::Duration for a nicer API. Do you think this would be a welcoming change?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.