/// <summary> /// Schedule an action. /// </summary> public static async void Schedule(this ITime time, Action action, DateTimeOffset due, CancellationToken token) { if (time == null) { throw new ArgumentNullException(nameof(time)); } if (action == null) { throw new ArgumentNullException(nameof(action)); } if (token.IsCancellationRequested) { return; } try { await time.Delay(due, token).ConfigureAwait(false); action(); } catch { /**/ } } /// <summary> /// Schedule an action. /// </summary> public static async void Schedule(this ITime time, Action action, TimeSpan due, CancellationToken token) { if (time == null) { throw new ArgumentNullException(nameof(time)); } if (action == null) { throw new ArgumentNullException(nameof(action)); } if (token.IsCancellationRequested) { return; } try { await time.Delay(due, token).ConfigureAwait(false); action(); } catch { /**/ } }
public async Task WaitAsync(CancellationToken cancellationToken = default) { try { _stateLogger.Log(_resourceName, LimiterStateEnum.WaitOnLock, waitTime: null); await _lock.WaitAsync(cancellationToken).ConfigureAwait(false); try { var now = _time.UtcNow.UtcDateTime; var startInterval = now - _interval; int count = 0; DateTime?firstInInterval = null; foreach (var item in _records) { if (item <= startInterval) { continue; } firstInInterval ??= item; ++count; } if (count < _maxCount) { _stateLogger.Log(_resourceName, LimiterStateEnum.Return, waitTime: null); _records.Add(now); return; } var firstExpired = firstInInterval !.Value + _interval; _stateLogger.Log(_resourceName, LimiterStateEnum.WaitUntilExpire, waitTime: firstExpired); await _time.Delay(firstExpired - now, cancellationToken).ConfigureAwait(false); _stateLogger.Log(_resourceName, LimiterStateEnum.Return, waitTime: null); _records.Add(firstExpired); } finally { _lock.Release(); } } catch (TaskCanceledException ex) { throw new OperationCanceledException("The operation was canceled.", ex, cancellationToken); } }