/// <summary> /// Gets a <see cref="RequestCounter"/> that counted the current request according the specified rule. /// </summary> /// <param name="request">The client request object.</param> /// <param name="rule">The throttle rule.</param> /// <returns>The corresponding counter for the request.</returns> public RequestCounter ProcessRequest(ClientRequest request, ThrottleRule rule) { if (rule.PeriodTimespan == null) { throw new InvalidOperationException("Throttle period time span is not set!"); } var key = GetStorageKey(request, rule); var counter = _counterStore.GetOrCreate( key, () => new RequestCounter { Timestamp = DateTime.UtcNow, TotalRequests = 0 }, rule.PeriodTimespan.Value); counter.Increment(); // Checks limit and enters cool down period by prolonging the counter expiration. if (counter.TotalRequests > rule.Limit && !counter.LimitExceeded) { counter.LimitExceeded = true; if (rule.CooldownTimespan.HasValue && DateTime.UtcNow + rule.CooldownTimespan.Value > counter.Timestamp + rule.PeriodTimespan.Value) { _counterStore.Set(key, counter, rule.CooldownTimespan.Value); } } return(counter); }
public RateLimitCounter Process(RequestIdentity requestIdentity, CounterRule rule) { var counter = new RateLimitCounter { Timestamp = DateTime.UtcNow, TotalRequests = 1 }; var counterId = GetRequestIdentityKey(requestIdentity, rule); // serial reads and writes lock (_processLocker) { var entry = _store.Get(counterId); if (entry.HasValue) { // entry has not expired if (entry.Value.Timestamp.AddSeconds(rule.Period) >= DateTime.UtcNow) { // increment request count var totalRequests = entry.Value.TotalRequests + 1; // deep copy counter = new RateLimitCounter { Timestamp = entry.Value.Timestamp, TotalRequests = totalRequests }; } } // stores: id (string) - timestamp (datetime) - total_requests (long) _store.Set(counterId, counter, TimeSpan.FromSeconds(rule.Period)); } return(counter); }