72 lines
2.6 KiB
C#
72 lines
2.6 KiB
C#
using System.Collections.Concurrent;
|
|
using adas_core.Application.Services.Interfaces;
|
|
|
|
namespace adas_core.Application.Services.Caching
|
|
{
|
|
/// <summary>
|
|
/// Implementación local del sistema de locking por clave.
|
|
/// Se basa en SemaphoreSlim y solo controla concurrencia DENTRO del proceso.
|
|
/// Para CacheService (in-memory).
|
|
/// </summary>
|
|
/// <!-- aidoc:v1 sig=ea44018 -->
|
|
public class InMemoryLockProvider : ILockProvider
|
|
{
|
|
private readonly ConcurrentDictionary<string, SemaphoreSlim> _locks = new(StringComparer.Ordinal);
|
|
|
|
/// <summary>
|
|
/// Crea u obtiene un semáforo asociado a la clave.
|
|
/// </summary>
|
|
/// <!-- aidoc:v1 sig=af8b85d body=29079e4 -->
|
|
private SemaphoreSlim GetOrCreate(string key)
|
|
{
|
|
return _locks.GetOrAdd(key, _ => new SemaphoreSlim(1, 1));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Intenta adquirir el lock por clave.
|
|
/// </summary>
|
|
/// <!-- aidoc-review:v1 severity=medium kind=missing_param
|
|
/// "Parameter 'key' is not documented" -->
|
|
/// <!-- aidoc-review:v1 severity=medium kind=missing_param
|
|
/// "Parameter 'timeout' is not documented" -->
|
|
/// <!-- aidoc-review:v1 severity=medium kind=missing_returns
|
|
/// "Return value (bool indicating acquisition success) is not documented" -->
|
|
public async Task<bool> AcquireAsync(string key, TimeSpan timeout)
|
|
{
|
|
var sem = GetOrCreate(key);
|
|
|
|
try
|
|
{
|
|
return await sem.WaitAsync(timeout).ConfigureAwait(false);
|
|
}
|
|
catch (ObjectDisposedException)
|
|
{
|
|
// Si el semáforo se eliminó entre medio, creamos uno nuevo.
|
|
_locks.TryRemove(key, out _);
|
|
return await GetOrCreate(key).WaitAsync(timeout).ConfigureAwait(false);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Libera el lock (si existe y no está ya liberado).
|
|
/// </summary>
|
|
/// <!-- aidoc-review:v1 severity=medium kind=missing_param
|
|
/// "The 'key' parameter is not documented; only a <summary> is provided, with no <param name=\"key\"> tag describing the lock identifier." -->
|
|
public Task ReleaseAsync(string key)
|
|
{
|
|
if (!_locks.TryGetValue(key, out var sem))
|
|
return Task.CompletedTask;
|
|
|
|
try
|
|
{
|
|
sem.Release();
|
|
}
|
|
catch (SemaphoreFullException)
|
|
{
|
|
// Idempotencia: ignoramos exceso de releases
|
|
}
|
|
|
|
return Task.CompletedTask;
|
|
}
|
|
}
|
|
} |