Exemplo n.º 1
0
        /// <summary>
        /// request can open rateLimit
        /// </summary>
        /// <param name="context"></param>
        /// <param name="methodCacheName"></param>
        /// <returns></returns>
        private async Task <(bool, EnableRateLimitAttribute)> RequestNeedRateLimitAsync(HttpContext context, string methodCacheName)
        {
            EnableRateLimitAttribute enableRateLimitAttribute = null;
            bool specialRuleResult = _specialRule != null &&
                                     _specialRule.MethodList != null &&
                                     _specialRule.MethodList.Any() &&
                                     _specialRule.MethodList.Contains(methodCacheName);

            if (!specialRuleResult)
            {
                //wheather need RateLimit
                var endpoint = GetEndpoint(context);
                if (endpoint != null)
                {
                    enableRateLimitAttribute = endpoint.Metadata.GetMetadata <EnableRateLimitAttribute>();
                    if (enableRateLimitAttribute == null)
                    {
                        await _next(context);

                        return(false, enableRateLimitAttribute);
                    }
                    var disableRateLimitAttribute = endpoint.Metadata.GetMetadata <DisableRateLimitAttribute>();
                    if (disableRateLimitAttribute != null)
                    {
                        await _next(context);

                        return(false, enableRateLimitAttribute);
                    }
                }
                else
                {
                    await _next(context);

                    return(false, enableRateLimitAttribute);
                }
            }
            return(true, enableRateLimitAttribute);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Asynchronous processing of Middleware
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public async Task Invoke(HttpContext context)
        {
            #region check whether need RateLimit  and local Attribute is prority then other rules

            string methodCacheName     = ContextMethodNameHandler(context);
            var    requestNeedRateLimt = await RequestNeedRateLimitAsync(context, methodCacheName);

            if (!requestNeedRateLimt.Item1)
            {
                return;
            }
            EnableRateLimitAttribute enableRateLimitAttribute = requestNeedRateLimt.Item2;
            #endregion check whether need RateLimit  and local Attribute is prority then other rules

            //local method attribute
            var getMethodAttrRateLimitData = GetRateLimitTypeAttributeData(context);

            // context.Items.Add("PollyRequire", _specialRule != null ? _specialRule.EnablePolly : false);
            await DoOnBeforeCheck(context, _algorithm).ConfigureAwait(false);

            AlgorithmCheckResult checkResult;//= await _algorithm.CheckAsync(context);

            #region Polly

            bool enablePolly = enableRateLimitAttribute == null ? (_specialRule != null ? _specialRule.EnablePolly : false) : enableRateLimitAttribute.EnablePolly;
            if (enablePolly)
            {
                checkResult = await PollyRateLimitAdvancedCircuitBreakerAsync(context.Request.Path.Value, enableRateLimitAttribute)
                              .ExecuteAsync(async() =>
                {
                    return(await _algorithm.CheckAsync(context, getMethodAttrRateLimitData));
                });
            }
            else
            {
                checkResult = await _algorithm.CheckAsync(context, getMethodAttrRateLimitData);
            }

            #endregion Polly

            await DoOnAfterCheck(context, checkResult).ConfigureAwait(false);

            if (checkResult.IsLimit)
            {
                if (checkResult.RuleCheckResults != null && checkResult.RuleCheckResults.Any())
                {
                    var checkException = checkResult.RuleCheckResults.FirstOrDefault(x => x.RateLimitExceptionThrow == true);
                    if (checkException != null)
                    {
                        throw new RateLimitException(methodCacheName);
                    }
                }
                await DoOnTriggered(context, checkResult).ConfigureAwait(false);

                context.Response.StatusCode = _error.HttpStatusCode;
                await SetHeaders(context, checkResult).ConfigureAwait(false);
                await ReponseWithTooManyRequests(context, checkResult).ConfigureAwait(false);
            }
            else
            {
                await DoOnBreforUntriggeredDoNext(context, checkResult).ConfigureAwait(false);

                await DoLeakyBucketWait(checkResult).ConfigureAwait(false);

                //Debug.WriteLine("R-Count" + checkResult.RuleCheckResults.First().Count + " " + DateTimeOffset.Now.ToString("mm:ss.fff"));
                await _next(context);

                await DoOnAfterUntriggeredDoNext(context, checkResult).ConfigureAwait(false);
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// rateLimit exception
        /// </summary>
        /// <returns></returns>
        private static AsyncPolicy <AlgorithmCheckResult> PollyRateLimitAdvancedCircuitBreakerAsync(string policyKey, EnableRateLimitAttribute enableRateLimitAttribute)
        {
            var getResult = _getPollyObj.TryGetValue(policyKey, out AsyncPolicy <AlgorithmCheckResult> pollyObj);

            if (getResult)
            {
                return(pollyObj);
            }
            int      retryCount       = enableRateLimitAttribute == null ? 1 : enableRateLimitAttribute.RetryCount;
            double   failureThreshold = enableRateLimitAttribute == null ? 0.75 : enableRateLimitAttribute.FailureThreshold;
            TimeSpan samplingDuration = enableRateLimitAttribute == null?TimeSpan.FromSeconds(10) : enableRateLimitAttribute.SamplingDuration;

            int      minimumThroughput = enableRateLimitAttribute == null ? 100 : enableRateLimitAttribute.MinimumThroughput;
            TimeSpan durationOfBreak   = enableRateLimitAttribute == null?TimeSpan.FromSeconds(10) : enableRateLimitAttribute.DurationOfBreak;

            var breakPolicy = Policy <AlgorithmCheckResult> .Handle <RateLimitException>().AdvancedCircuitBreakerAsync(
                failureThreshold: failureThreshold,
                samplingDuration: samplingDuration,
                minimumThroughput: minimumThroughput,
                durationOfBreak: durationOfBreak,
                onBreak: (r, t) =>
            {
                Console.WriteLine("onbreak");
            },
                onReset: () =>
            {
                Console.WriteLine("onReset");
            },
                onHalfOpen: () =>
            {
                Console.WriteLine("onHalfOpen");
            }
                );

            var retry = Policy <AlgorithmCheckResult> .Handle <RateLimitException>().WaitAndRetryAsync(retryCount, i => TimeSpan.FromMilliseconds(100 * i));

            var message = new AlgorithmCheckResult(new List <RuleCheckResult>()
            {
                new RuleCheckResult()
                {
                    IsLimit = true
                }
            })
            {
            };
            var fallback = Policy <AlgorithmCheckResult> .Handle <BrokenCircuitException>().FallbackAsync(message);

            var fallbackBreak = Policy.WrapAsync(fallback, retry, breakPolicy).WithPolicyKey(policyKey);

            _getPollyObj.TryAdd(policyKey, fallbackBreak);
            return(fallbackBreak);
        }