public virtual async Task <RateLimitCounter> ProcessRequestAsync(ClientRequestIdentity requestIdentity, RateLimitRule rule, CancellationToken cancellationToken = default) { var counter = new RateLimitCounter { Timestamp = DateTime.UtcNow, Count = 1 }; var counterId = BuildCounterKey(requestIdentity, rule); // serial reads and writes on same key using (await AsyncKeyLock.WriterLockAsync(counterId).ConfigureAwait(false)) { var entry = await _counterStore.GetAsync(counterId, cancellationToken); // entry has not expired if (entry.HasValue && entry.Value.Timestamp + rule.PeriodTimespan.Value >= DateTime.UtcNow) { // increment request count var totalCount = entry.Value.Count + _config.RateIncrementer?.Invoke() ?? 1; // deep copy counter = new RateLimitCounter { Timestamp = entry.Value.Timestamp, Count = totalCount }; } // stores: id (string) - timestamp (datetime) - total_requests (long) await _counterStore.SetAsync(counterId, counter, rule.PeriodTimespan.Value, cancellationToken); } return(counter); }