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));
            }
        }
Exemple #3
0
        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));
                            },
                        }
                    });
                }
            }
        }