private DbRateLimiterConfig GetDbConfig(RateLimiterConfig config) { var dbConfig = new DbRateLimiterConfig { RequestTimeout = config.RequestTimeout }; switch (config.RateLimiterType) { case RateLimiterType.Burst: dbConfig.MaxTokens = config.IntervalCount; dbConfig.OperationsInterval = config.IntervalRange; break; case RateLimiterType.Interval: dbConfig.MaxTokens = 1; dbConfig.OperationsInterval = TimeSpanDivision(config.IntervalRange, config.IntervalCount); break; default: throw new ArgumentOutOfRangeException($"Unknown RateLimiter type of {config.RateLimiterType:G}"); } dbConfig.StorageKey = GetStorageKey( config.Key, dbConfig.MaxTokens, dbConfig.OperationsInterval.Milliseconds); return(dbConfig); }
private DateTimeOffset TryAllocateToken(DbRateLimiterConfig config) { var startDate = DateTimeOffset.UtcNow; for (var current = startDate; current - startDate < config.RequestTimeout; current = DateTimeOffset.UtcNow) { var expirationDate = current.Subtract(config.OperationsInterval); var tokenCount = _repo.GetTokenCount(config.StorageKey, expirationDate); if (tokenCount >= config.MaxTokens) { //TODO: dynamic backoff sleep or retry class (move to top) System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5)); continue; } _repo.AllocateToken(config); return(current); } throw new RateLimitTimeoutException($"Could not get a token in '{config.RequestTimeout.Seconds}' seconds"); }