private Tuple <bool, long> InnerCheckSingleRule(string target, int amount, FixedWindowRule currentRule) { bool locked = CheckLocked(target); if (locked) { return(Tuple.Create(true, -1L)); } var currentTime = _timeProvider.GetCurrentLocalTime(); var startTime = AlgorithmStartTime.ToSpecifiedTypeTime(currentTime, currentRule.StatWindow, currentRule.StartTimeType); Tuple <bool, long> incrementResult; lock (target) { DateTimeOffset expireTime = startTime.Add(currentRule.StatWindow); incrementResult = SimpleIncrement(target, amount, expireTime, currentRule.LimitNumber); } var checkResult = incrementResult.Item1; if (checkResult) { if (currentRule.LockSeconds > 0) { TryLock(target, currentTime, TimeSpan.FromSeconds(currentRule.LockSeconds)); return(Tuple.Create(checkResult, incrementResult.Item2)); } } return(Tuple.Create(checkResult, incrementResult.Item2)); }
private IAlgorithm GetFixedWindowProcessor(string storageType, int limitNumber) { var fixedWindowRules = new FixedWindowRule[] { new FixedWindowRule() { Id = Guid.NewGuid().ToString(), StatWindow = TimeSpan.FromSeconds(1), LimitNumber = limitNumber, ExtractTarget = (request) => { return((request as SimulationRequest).RequestResource); }, CheckRuleMatching = (request) => { return(true); } } }; if (storageType == "redis") { return(new RedisFixedWindowAlgorithm(fixedWindowRules, redisClient)); } else { return(new InProcessFixedWindowAlgorithm(fixedWindowRules)); } }
private IAlgorithm GetAlgorithm(string storageType, TimeSpan statWindow, StartTimeType startTimeType, int limitNumber, int lockSeconds) { var fixedWindowRules = new FixedWindowRule[] { new FixedWindowRule() { Id = Guid.NewGuid().ToString(), StatWindow = statWindow, StartTimeType = startTimeType, LimitNumber = limitNumber, LockSeconds = lockSeconds, ExtractTarget = (request) => { return((request as SimulationRequest).RequestResource); }, CheckRuleMatching = (request) => { return(true); }, ExtractTargetAsync = (request) => { return(Task.FromResult((request as SimulationRequest).RequestResource)); }, CheckRuleMatchingAsync = (request) => { return(Task.FromResult(true)); }, } }; if (storageType == "redis") { var redisClient = StackExchange.Redis.ConnectionMultiplexer.Connect("127.0.0.1"); return(new RedisFixedWindowAlgorithm(fixedWindowRules, redisClient)); } else { return(new InProcessFixedWindowAlgorithm(fixedWindowRules)); } }
private static void DoFixedWindow() { var fixedWindowRules = new FixedWindowRule[] { new FixedWindowRule() { Id = "1", StatWindow = TimeSpan.FromSeconds(1), LimitNumber = 30, ExtractTarget = (request) => { return((request as SimulationRequest).RequestResource); }, CheckRuleMatching = (request) => { return(true); }, } }; var timeProvider = new LocalTimeProvider(); var algorithm = new InProcessFixedWindowAlgorithm(fixedWindowRules, timeProvider, true); // var redisClient = StackExchange.Redis.ConnectionMultiplexer.Connect("127.0.0.1"); // var algorithm = new RedisFixedWindowAlgorithm(fixedWindowRules, redisClient, timeProvider, true); for (int i = 0; i < 80; i++) { var result = algorithm.Check(new SimulationRequest() { RequestId = Guid.NewGuid().ToString(), RequestResource = "home", Parameters = new Dictionary <string, string>() { { "from", "sample" }, } }, null); var isLimit = result.IsLimit; Console.WriteLine($"IsLimit:{isLimit}"); foreach (var r in result.RuleCheckResults) { Console.WriteLine($"[{i}] Target:{r.Target},IsLimit:{r.IsLimit},Count:{r.Count}."); // If you need to return when a rule is restricted, you can use break. // However, this is not recommended, the count will be lost for the rule is not triggered // if (r.IsLimit) // { // break; // } } // // Do not use the LINQ method after traversal or multiple times in a single request. // // This results in duplicate counts. // var limit = result.Any(d=>d.IsLimit); // var r = result.First(); // Console.WriteLine($"[{i}] Target:{r.Target},IsLimit:{r.IsLimit},Count:{r.Count}."); if (i == 40) { algorithm.UpdateRules(new FixedWindowRule[] { new FixedWindowRule() { Id = "1", StatWindow = TimeSpan.FromSeconds(1), LimitNumber = 60, ExtractTarget = (request) => { return((request as SimulationRequest).RequestResource); }, CheckRuleMatching = (request) => { return(true); }, } }); } if (i == 60) { algorithm.UpdateRules(new FixedWindowRule[] { new FixedWindowRule() { Id = "1", StatWindow = TimeSpan.FromSeconds(1), LimitNumber = 40, ExtractTarget = (request) => { return((request as SimulationRequest).RequestResource); }, CheckRuleMatching = (request) => { return(true); }, } }); } } }
private static async Task DoFixedWindowAsync() { var fixedWindowRules = new FixedWindowRule[] { new FixedWindowRule() { Id = "1", StatWindow = TimeSpan.FromSeconds(1), LimitNumber = 30, ExtractTargetAsync = (request) => { return(Task.FromResult((request as SimulationRequest).RequestResource)); }, CheckRuleMatchingAsync = (request) => { return(Task.FromResult(true)); }, } }; var timeProvider = new LocalTimeProvider(); var algorithm = new InProcessFixedWindowAlgorithm(fixedWindowRules, timeProvider, true); // var redisClient = StackExchange.Redis.ConnectionMultiplexer.Connect("127.0.0.1"); // var algorithm = new RedisFixedWindowAlgorithm(fixedWindowRules, redisClient, timeProvider, true); for (int i = 0; i < 80; i++) { var result = algorithm.CheckAsync(new SimulationRequest() { RequestId = Guid.NewGuid().ToString(), RequestResource = "home", Parameters = new Dictionary <string, string>() { { "from", "sample" }, } }, null); var resultValue = await result; foreach (var r in resultValue.RuleCheckResults) { Console.WriteLine($"[{i}] Target:{r.Target},IsLimit:{r.IsLimit},Count:{r.Count}."); } if (i == 40) { algorithm.UpdateRules(new FixedWindowRule[] { new FixedWindowRule() { Id = "1", StatWindow = TimeSpan.FromSeconds(1), LimitNumber = 60, ExtractTargetAsync = (request) => { return(Task.FromResult((request as SimulationRequest).RequestResource)); }, CheckRuleMatchingAsync = (request) => { return(Task.FromResult(true)); }, } }); } if (i == 60) { algorithm.UpdateRules(new FixedWindowRule[] { new FixedWindowRule() { Id = "1", StatWindow = TimeSpan.FromSeconds(1), LimitNumber = 40, ExtractTargetAsync = (request) => { return(Task.FromResult((request as SimulationRequest).RequestResource)); }, CheckRuleMatchingAsync = (request) => { return(Task.FromResult(true)); }, } }); } } }