internal static async Task AddAcquisitionRequestAsync(this IDatabase db, DSemaphoreContext sempahoreContext, double currentTime, long counter) { // add the current time await db.SortedSetAddAsync(sempahoreContext.SemaphoreName, sempahoreContext.Id, currentTime); // add the current count await db.SortedSetAddAsync(sempahoreContext.CounterSetName, sempahoreContext.Id, counter); }
private async Task <bool> CanBeAcquiredAsync(DSemaphoreContext sempahoreContext, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var currentPosition = await _db.SortedSetRankAsync(sempahoreContext.CounterSetName, sempahoreContext.Id); return(currentPosition.HasValue && currentPosition.Value < _maxCount); }
/// <summary> /// Exits the <see cref="DSemaphoreContext"/>. /// </summary> private async Task ReleaseAsync(DSemaphoreContext context, CancellationToken cancellationToken) { await _locker.WaitAsync(cancellationToken); try { if (!_contexts.ContainsKey(context.Id)) { return; } await _db.RemoveSemaphoreAsync(context); _contexts.TryRemove(context.Id, out _); } finally { _locker.Release(); } }
internal static async Task RemoveSemaphoreAsync(this IDatabase db, DSemaphoreContext sempahoreContext) { await db.SortedSetRemoveAsync(sempahoreContext.SemaphoreName, sempahoreContext.Id); await db.SortedSetRemoveAsync(sempahoreContext.CounterSetName, sempahoreContext.Id); }
internal static async Task RemoveObsoleteAcquisitionRequestsAsync(this IDatabase db, DSemaphoreContext sempahoreContext, double outdatedLimit) { await db.SortedSetRemoveRangeByScoreAsync(sempahoreContext.SemaphoreName, 0, outdatedLimit); await db.SortedSetCombineAndStoreAsync( SetOperation.Intersect, sempahoreContext.CounterSetName, new RedisKey[] { sempahoreContext.CounterSetName, sempahoreContext.SemaphoreName }, new double[] { 1, 0 } ); }
public async Task <bool> WaitAsync(TimeSpan timeout, string id = null, CancellationToken cancellationToken = default) { CheckDispose(); if (timeout < _minimumTimeoutTime) { throw new ArgumentOutOfRangeException($"{nameof(timeout)} cannot be less than {_minimumTimeoutTime}"); } if (cancellationToken.IsCancellationRequested) { return(await Task.FromCanceled <bool>(cancellationToken)); } using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _cancellationToken, default); id ??= Guid.NewGuid().ToString(); var semaphoreContext = _contexts.GetOrAdd(id, s => new Lazy <DSemaphoreContext>(() => DSemaphoreContext.CreateNewContext(id, _semaphoreName))).Value; var isAcquired = false; if (semaphoreContext.CreationDate < DateTime.Now) { var currentTime = semaphoreContext.CreationDate.ToOADate(); var obsoleteSemaphoreLimit = (semaphoreContext.CreationDate - timeout).ToOADate(); await _db.RemoveObsoleteAcquisitionRequestsAsync(semaphoreContext, obsoleteSemaphoreLimit); var currentCounter = await _db.StringIncrementAsync(semaphoreContext.CounterName); await _db.AddAcquisitionRequestAsync(semaphoreContext, currentTime, currentCounter); var stopwatch = Stopwatch.StartNew(); while (stopwatch.Elapsed <= timeout) { isAcquired = await CanBeAcquiredAsync(semaphoreContext, cts.Token); if (isAcquired) { break; } await Task.Delay(_retryTime, cancellationToken); } } await ReleaseAsync(semaphoreContext, cts.Token); cts.Cancel(); return(isAcquired); }