RedisDistributedLock Implementation in Aspect-Oriented Programming (AOP)

Aspect-Oriented Programming (AOP) lends itself well to distributed resource management tasks such as locking. Below is an implementation of a Redis-based distributed lock using the StackExchange.Redis library, focusing on resource isolation and concurrency control.


RedisDistributedLock Class

Here is the complete implementation:

using StackExchange.Redis;
using System;
using System.Threading.Tasks;

public class RedisDistributedLock : IDisposable
{
    private readonly IDatabase _redisDb;
    private readonly string _lockKey;
    private readonly string _lockValue;
    private bool _acquired;

    public RedisDistributedLock(IDatabase redisDb, string resourceKey)
    {
        _redisDb = redisDb;
        _lockKey = $"lock:{resourceKey}";
        _lockValue = Guid.NewGuid().ToString(); // random token
    }

    /// <summary>
    /// Attempts to acquire a lock for the specified lock key with a given expiry.
    /// </summary>
    /// <param name="expiry">Duration for lock expiry.</param>
    /// <returns>True if the lock was acquired; otherwise, false.</returns>
    public async Task<bool> AcquireAsync(TimeSpan expiry)
    {
        _acquired = await _redisDb.StringSetAsync(
            key: _lockKey,
            value: _lockValue,
            expiry: expiry,
            when: When.NotExists);
        return _acquired;
    }

    /// <summary>
    /// Releases the lock if it’s still held by this instance.
    /// </summary>
    public async Task ReleaseAsync()
    {
        if (_acquired)
        {
            // Verify token before deleting.
            var currentValue = await _redisDb.StringGetAsync(_lockKey);
            if (currentValue == _lockValue)
            {
                await _redisDb.KeyDeleteAsync(_lockKey);
            }
            _acquired = false;
        }
    }

    /// <summary>
    /// Cleanup method ensuring the lock is freed.
    /// </summary>
    public void Dispose()
    {
        ReleaseAsync().GetAwaiter().GetResult();
    }
}

Acquiring and Releasing the Lock

Using the RedisDistributedLock class to acquire and release locks ensures concurrency control in distributed systems.

// Acquire the lock, do some work, then release it
var lockManager = new RedisDistributedLock(redisDatabase, "someResourceKey");
if (await lockManager.AcquireAsync(TimeSpan.FromSeconds(30)))
{
    try
    {
        // Do protected work here...
    }
    finally
    {
        await lockManager.ReleaseAsync();
    }
}
else
{
    // Could not acquire the lock; handle accordingly
}

Key Features and Advantages

  1. Isolation: Each lock instance operates independently, ensuring safety in concurrent environments.
  2. Token Verification: Prevents accidental or malicious lock overrides by matching tokens before releasing locks.
  3. Efficiency: Leverages Redis’s high-speed in-memory capabilities for rapid lock acquisition and release.

Redis-based distributed locking, combined with AOP principles, offers a reliable solution for managing shared resources in distributed systems.

Related Posts