Last active
July 7, 2020 15:02
-
-
Save oguzhaneren/b41354ebc65ddc977161defb4571d931 to your computer and use it in GitHub Desktop.
Distributed Lock with redis (.net)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class DistributedLock | |
: IAsyncDisposable | |
{ | |
private const string AtomicReleaseScript = @" | |
if redis.call(""get"",KEYS[1]) == ARGV[1] then | |
return redis.call(""del"",KEYS[1]) | |
else | |
return 0 | |
end | |
"; | |
private const CommandFlags Flags = CommandFlags.DemandMaster; | |
private readonly string _key; | |
private readonly TimeSpan? _expire; | |
private readonly IDatabase _redis; | |
private readonly string _uniqueLockKey; | |
private bool _isLocked; | |
public bool IsLocked => _isLocked; | |
private DistributedLock(string key, IDatabase redisDatabase, TimeSpan? expire) | |
{ | |
_key = key; | |
_expire = expire; | |
_redis = redisDatabase; | |
_uniqueLockKey = Guid.NewGuid().ToString("N"); | |
} | |
private async ValueTask TryAcquireLock() | |
{ | |
_isLocked = await _redis.StringSetAsync(_key, _uniqueLockKey, _expire, When.NotExists, Flags); | |
} | |
public static async ValueTask<DistributedLock> AcquireLock(string key, IDatabase redisDatabase, TimeSpan? expire = null) | |
{ | |
var distributedLock = new DistributedLock(key, redisDatabase, expire); | |
await distributedLock.TryAcquireLock(); | |
return distributedLock; | |
} | |
public async ValueTask Unlock() | |
{ | |
if (!_isLocked) | |
{ | |
return; | |
} | |
RedisKey[] keys = {_key}; | |
RedisValue[] values = {_uniqueLockKey}; | |
await _redis.ScriptEvaluateAsync(AtomicReleaseScript, keys, values); | |
} | |
public ValueTask DisposeAsync() | |
{ | |
return Unlock(); | |
} | |
} | |
public static class RedisExtensions | |
{ | |
public static ValueTask<DistributedLock> AcquireLock(this IDatabase redisDatabase, string key, TimeSpan? expire = null) | |
{ | |
return DistributedLock.AcquireLock(key, redisDatabase, expire); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment