public async Task TestUpdateRulesAsync(string storageType)
        {
            FixedWindowRule[] fixedWindowRules = CreateRules(50);

            IAlgorithm algorithm;

            if (storageType == "redis")
            {
                var redisClient = StackExchange.Redis.ConnectionMultiplexer.Connect("127.0.0.1");
                algorithm = new RedisFixedWindowAlgorithm(fixedWindowRules, redisClient, updatable: true);
            }
            else
            {
                algorithm = new InProcessFixedWindowAlgorithm(fixedWindowRules, updatable: true);
            }

            for (int i = 1; i <= 80; i++)
            {
                if (i == 61)
                {
                    var fixedWindowRules2 = CreateRules(60);
                    await algorithm.UpdateRulesAsync(fixedWindowRules2);
                }

                var result = await algorithm.CheckAsync(new SimulationRequest()
                {
                    RequestId       = Guid.NewGuid().ToString(),
                    RequestResource = "home",
                    Parameters      = new Dictionary <string, string>()
                    {
                        { "from", "sample" },
                    }
                });

                Console.WriteLine(i + ":" + result.IsLimit + "," + result.RuleCheckResults.First().Count);

                if ((i > 50 && i <= 60) || i > 70)
                {
                    Assert.AreEqual(true, result.IsLimit);
                }

                if (i <= 50 || (i >= 61 && i <= 70))
                {
                    Assert.AreEqual(false, result.IsLimit);
                }
            }
        }
        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));
                            },
                        }
                    });
                }
            }
        }