2024-07-15 21:38:47 +00:00
|
|
|
using Medallion.Threading.Redis;
|
2024-04-30 12:50:01 +00:00
|
|
|
using StackExchange.Redis;
|
|
|
|
|
|
|
|
|
|
namespace BotSharp.Core.Infrastructures;
|
|
|
|
|
|
|
|
|
|
public class DistributedLocker
|
|
|
|
|
{
|
|
|
|
|
private readonly BotSharpDatabaseSettings _settings;
|
2024-08-21 19:48:12 +00:00
|
|
|
private static ConnectionMultiplexer connection;
|
2024-04-30 12:50:01 +00:00
|
|
|
|
2024-07-15 21:38:47 +00:00
|
|
|
public DistributedLocker(BotSharpDatabaseSettings settings)
|
2024-04-30 12:50:01 +00:00
|
|
|
{
|
2024-07-15 21:38:47 +00:00
|
|
|
_settings = settings;
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-21 15:26:36 +00:00
|
|
|
public async Task<T> Lock<T>(string resource, Func<Task<T>> action, int timeoutInSeconds = 30)
|
2024-07-15 21:38:47 +00:00
|
|
|
{
|
2024-11-05 13:29:06 +00:00
|
|
|
await ConnectToRedisAsync();
|
2024-08-21 19:48:12 +00:00
|
|
|
|
2024-07-15 21:38:47 +00:00
|
|
|
var timeout = TimeSpan.FromSeconds(timeoutInSeconds);
|
2024-04-30 12:50:01 +00:00
|
|
|
|
2024-07-15 21:38:47 +00:00
|
|
|
var @lock = new RedisDistributedLock(resource, connection.GetDatabase());
|
|
|
|
|
await using (var handle = await @lock.TryAcquireAsync(timeout))
|
2024-04-30 12:50:01 +00:00
|
|
|
{
|
2024-08-21 15:26:36 +00:00
|
|
|
if (handle == null)
|
2024-04-30 12:50:01 +00:00
|
|
|
{
|
2024-07-15 21:38:47 +00:00
|
|
|
Serilog.Log.Logger.Error($"Acquire lock for {resource} failed due to after {timeout}s timeout.");
|
|
|
|
|
}
|
2024-08-21 15:26:36 +00:00
|
|
|
|
|
|
|
|
return await action();
|
2024-04-30 12:50:01 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-05 13:29:06 +00:00
|
|
|
public void Lock(string resource, Action action, int timeoutInSeconds = 30)
|
2024-04-30 12:50:01 +00:00
|
|
|
{
|
2024-11-05 13:29:06 +00:00
|
|
|
ConnectToRedis();
|
2024-04-30 12:50:01 +00:00
|
|
|
|
2024-08-21 19:48:12 +00:00
|
|
|
var timeout = TimeSpan.FromSeconds(timeoutInSeconds);
|
2024-08-21 18:41:52 +00:00
|
|
|
|
2024-07-15 21:38:47 +00:00
|
|
|
var @lock = new RedisDistributedLock(resource, connection.GetDatabase());
|
2024-11-05 13:29:06 +00:00
|
|
|
using (var handle = @lock.TryAcquire(timeout))
|
2024-04-30 12:50:01 +00:00
|
|
|
{
|
2024-08-21 16:23:24 +00:00
|
|
|
if (handle == null)
|
2024-04-30 12:50:01 +00:00
|
|
|
{
|
2024-07-15 21:38:47 +00:00
|
|
|
Serilog.Log.Logger.Error($"Acquire lock for {resource} failed due to after {timeout}s timeout.");
|
2024-04-30 12:50:01 +00:00
|
|
|
}
|
2024-11-05 13:29:06 +00:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
action();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ConnectToRedis()
|
|
|
|
|
{
|
|
|
|
|
if (connection == null)
|
|
|
|
|
{
|
|
|
|
|
connection = ConnectionMultiplexer.Connect(_settings.Redis);
|
2024-04-30 12:50:01 +00:00
|
|
|
}
|
|
|
|
|
}
|
2024-08-21 19:48:12 +00:00
|
|
|
|
2024-11-05 13:29:06 +00:00
|
|
|
private async Task ConnectToRedisAsync()
|
2024-08-21 19:48:12 +00:00
|
|
|
{
|
|
|
|
|
if (connection == null)
|
|
|
|
|
{
|
|
|
|
|
connection = await ConnectionMultiplexer.ConnectAsync(_settings.Redis);
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-04-30 12:50:01 +00:00
|
|
|
}
|