RedLock.net Documentation

repository·master·Indexed 21 days ago

https://github.com/samcook/redlock.net

A C# implementation of the Redlock distributed lock algorithm using StackExchange.Redis. It enables multiple processes to coordinate access to shared resources across different machines via the RedLockFactory, supporting both automatic connection management and existing ConnectionMultiplexer instances.

Tokens
2K
Snippets
6
Records
6
Agent score
27%

What's inside RedLock.net

  1. How replicated Redis instances work with RedLock.net

    master

    The Redlock algorithm is designed for independent Redis instances. However, RedLock.net supports replicated master/slave sets by treating each RedLockEndPoint as a single unit.

    To use replicated instances, provide a RedLockEndPoint where the EndPoints property contains the list of servers in that replication set.

    Risks of using replication:

    • Write operations: All Redlock operations (Lock, Extend, Unlock) are writes and must be performed on the master. If a master fails and a slave is not automatically promoted, the instance becomes unusable.
    • Race conditions: If a master fails after acquiring a lock but before propagating it to slaves, a newly promoted master might not have the lock, potentially allowing another process to acquire it simultaneously.
    • Stale locks: If a master fails after releasing a lock but before propagation, the lock may persist in the slaves until the original expiry time is reached.
    // Example: Using multiple independent replicated sets
    var redlockEndPoints = new List<RedLockEndPoint>
    {
    	new RedLockEndPoint
    	{
    		EndPoints = 
    		{
    			new DnsEndPoint("replicatedset1-server1", 6379),
    			new DnsEndPoint("replicatedset1-server2", 6379),
    			new DnsEndPoint("replicatedset1-server3", 6379)
    		}
    	},
    	new RedLockEndPoint
    	{
    		EndPoints = 
    		{
    			new DnsEndPoint("replicatedset2-server1", 6379),
    			new DnsEndPoint("replicatedset2-server2", 6379),
    			new DnsEndPoint("replicatedset2-server3", 6379)
    		}
    	},
    	new RedLockEndPoint
    	{
    		EndPoint = new DnsEndPoint("independent-server", 6379)
    	}
    };
    
    var redlockFactory = RedLockFactory.Create(redlockEndPoints);
  2. Install RedLock.net via NuGet

    master

    RedLock.net is available as a NuGet package. Search for RedLock.net in your package manager.

    Compatibility Note:

    • RedLock 2.2.0+ requires StackExchange.Redis 2.0+.
    • If you must use StackExchange.Redis 1.x, use RedLock.net 2.1.0.
    dotnet add package RedLock.net
  3. Acquire a distributed lock

    master

    To use a lock, call CreateLockAsync (or the synchronous Create method) on your RedLockFactory instance within a using block.

    Crucial Step: You must check the IsAcquired property inside the block. A lock is only considered successfully acquired if it can be set in more than half of the configured Redis instances.

    The lock is automatically released when the using block is exited. If a process crashes, the lock will eventually expire in Redis based on the provided expiry time.

    var resource = "the-thing-we-are-locking-on";
    var expiry = TimeSpan.FromSeconds(30);
    
    // Immediate attempt (gives up if not available)
    await using (var redLock = await redlockFactory.CreateLockAsync(resource, expiry))
    {
    	// ALWAYS check IsAcquired
    	if (redLock.IsAcquired)
    	{
    		// Perform protected work
    	}
    }
  4. Initialize RedLockFactory

    master

    The RedLockFactory is the central object used to manage distributed locks. You should create it once during application startup, reuse it throughout your application, and dispose of it when the application shuts down.

    You can initialize it in two ways:

    1. Automatic Connection Management: Pass a list of RedLockEndPoint objects. RedLock will manage its own StackExchange.Redis connections.
    2. Existing Connections: Pass a list of RedLockMultiplexer objects. This allows you to reuse existing ConnectionMultiplexer instances.
    // Option 1: RedLock maintains its own connections
    var endPoints = new List<RedLockEndPoint>
    {
    	new DnsEndPoint("redis1", 6379),
    	new DnsEndPoint("redis2", 6379),
    	new DnsEndPoint("redis3", 6379)
    };
    var redlockFactory = RedLockFactory.Create(endPoints);
    
    // Option 2: Use existing StackExchange.Redis connections
    var existingConnectionMultiplexer1 = ConnectionMultiplexer.Connect("redis1:6379");
    var existingConnectionMultiplexer2 = ConnectionMultiplexer.Connect("redis2:6379");
    var existingConnectionMultiplexer3 = ConnectionMultiplexer.Connect("redis3:6379");
    
    var multiplexers = new List<RedLockMultiplexer>
    {
    	existingConnectionMultiplexer1,
    	existingConnectionMultiplexer2,
    	existingConnectionMultiplexer3
    };
    var redlockFactory = RedLockFactory.Create(multiplexers);
  5. Configure RedLock for Azure Redis Cache

    master

    When connecting to Azure Redis Cache, you must enable SSL and provide your access key via the RedLockEndPoint configuration.

    var azureEndPoint = new RedLockEndPoint
    {
    	EndPoint = new DnsEndPoint("YOUR_CACHE.redis.cache.windows.net", 6380),
    	Password = "YOUR_ACCESS_KEY",
    	Ssl = true
    };
  6. Acquire a lock with retries and waiting

    master

    If you want the application to wait for a lock to become available instead of giving up immediately, use the overload of CreateLockAsync that accepts wait and retry parameters.

    • wait: The total amount of time to block and retry before giving up.
    • retry: The interval between retry attempts.
    • CancellationToken: You can pass a token to cancel the blocking wait.
    var resource = "the-thing-we-are-locking-on";
    var expiry = TimeSpan.FromSeconds(30);
    var wait = TimeSpan.FromSeconds(10);
    var retry = TimeSpan.FromSeconds(1);
    
    // Blocks until acquired or 'wait' timeout is reached
    await using (var redLock = await redlockFactory.CreateLockAsync(resource, expiry, wait, retry))
    {
    	if (redLock.IsAcquired)
    	{
    		// Do stuff
    	}
    }
    var resource = "the-thing-we-are-locking-on";
    var expiry = TimeSpan.FromSeconds(30);
    var wait = TimeSpan.FromSeconds(10);
    var retry = TimeSpan.FromSeconds(1);
    
    // blocks until acquired or 'wait' timeout
    await using (var redLock = await redlockFactory.CreateLockAsync(resource, expiry, wait, retry)) // there are also non async Create() methods
    {
    	// make sure we got the lock
    	if (redLock.IsAcquired)
    	{
    		// do stuff
    	}
    }
    // the lock is automatically released at the end of the using block