Example #1
0
        public static void ConfigureRateLimiting(HttpFilterCollection filters)
        {
            var rateLimitingPolicyParametersProvider  = new SampleRateLimitingClientPolicyProvider();
            var globalRateLimitingClientPolicyManager =
                new RateLimitingPolicyManager(rateLimitingPolicyParametersProvider)
                .AddPathToWhiteList("/api/unlimited")
                .AddPoliciesForAllEndpoints(new List <AllowedConsumptionRate>()
            {
                new AllowedConsumptionRate(100, RateLimitUnit.PerMinute)
            }, allowAttributeOverride: true, name: "StaticPolicy_2")
                .AddEndpointPolicy("/api/globallylimited/{id}", "GET", new List <AllowedConsumptionRate>()
            {
                new AllowedConsumptionRate(5, RateLimitUnit.PerMinute),
                new AllowedConsumptionRate(8, RateLimitUnit.PerHour)
            }, true, "StaticPolicy_0")
                .AddEndpointPolicy("/api/globallylimited/{id}/sub/{subid}", RateLimitPolicy.AllHttpMethods,
                                   new List <AllowedConsumptionRate>()
            {
                new AllowedConsumptionRate(2, RateLimitUnit.PerMinute)
            }, true, "StaticPolicy_1");

            #region Setting up the Redis rate limiter
            var redisRateLimiterSettings = new RedisRateLimiterSettings();

            ConfigureRateLimitingSettings(redisRateLimiterSettings);

            var rateLimitCacheProvider = new SlidingTimeWindowRateLimiter(
                redisRateLimiterSettings.RateLimitRedisCacheConnectionString,
                onThrottled: (rateLimitingResult) =>
            {
                //_logger.LogInformation(
                //    "Request throttled for client {ClientId} and endpoint {Endpoint}",
                //    rateLimitingResult.CacheKey.RequestId,
                //    rateLimitingResult.CacheKey.RouteTemplate);
            },
                circuitBreaker: new DefaultCircuitBreaker(redisRateLimiterSettings.FaultThreshholdPerWindowDuration,
                                                          redisRateLimiterSettings.FaultWindowDurationInMilliseconds, redisRateLimiterSettings.CircuitOpenIntervalInSecs,
                                                          onCircuitOpened: () =>
            {
                //_logger.LogWarning("Rate limiting circuit opened")
            },
                                                          onCircuitClosed: () =>
            {
                //logger.LogWarning("Rate limiting circuit closed")
            }));

            #endregion

            filters.Add(new RateLimitingFilter(new
                                               RateLimiter(rateLimitCacheProvider, globalRateLimitingClientPolicyManager), filters));
        }
Example #2
0
 private static void ConfigureRateLimitingSettings(RedisRateLimiterSettings redisRateLimiterSettings)
 {
     redisRateLimiterSettings.RateLimitRedisCacheConnectionString =
         ConfigurationManager.AppSettings["RedisRateLimiterSettings:RateLimitRedisCacheConnectionString"];
     redisRateLimiterSettings.CircuitOpenIntervalInSecs =
         Int32.Parse(ConfigurationManager.AppSettings["RedisRateLimiterSettings:CircuitOpenIntervalInSecs"]);
     redisRateLimiterSettings.ConnectionTimeoutInMilliseconds =
         Int32.Parse(ConfigurationManager.AppSettings["RedisRateLimiterSettings:ConnectionTimeoutInMilliseconds"]);
     redisRateLimiterSettings.SyncTimeoutInMilliseconds =
         Int32.Parse(ConfigurationManager.AppSettings["RedisRateLimiterSettings:SyncTimeoutInMilliseconds"]);
     redisRateLimiterSettings.FaultThreshholdPerWindowDuration =
         Int32.Parse(ConfigurationManager.AppSettings["RedisRateLimiterSettings:FaultThreshholdPerWindowDuration"]);
     redisRateLimiterSettings.FaultWindowDurationInMilliseconds =
         Int32.Parse(ConfigurationManager.AppSettings["RedisRateLimiterSettings:FaultWindowDurationInMilliseconds"]);
     redisRateLimiterSettings.CountThrottledRequests =
         Boolean.Parse(ConfigurationManager.AppSettings["RedisRateLimiterSettings:CountThrottledRequests"]);
 }
Example #3
0
        public static void ConfigureRateLimiting(HttpFilterCollection filters)
        {
            #region Setting up the Redis rate limiter
            var redisRateLimiterSettings = new RedisRateLimiterSettings();

            ConfigureRateLimitingSettings(redisRateLimiterSettings);

            var rateLimitCacheProvider = new LeakyBucketRateLimiter(
                redisRateLimiterSettings.RateLimitRedisCacheConnectionString,
                onException: (ex) =>
            {
                //_logger.LogError("Error connecting to Redis")
            },
                circuitBreaker: new DefaultCircuitBreaker(redisRateLimiterSettings.FaultThreshholdPerWindowDuration,
                                                          redisRateLimiterSettings.FaultWindowDurationInMilliseconds, redisRateLimiterSettings.CircuitOpenIntervalInSecs,
                                                          onCircuitException: (ex) =>
            {
                //_logger.LogError("Rate limiting circuit error")
            },
                                                          onCircuitOpened: () =>
            {
                //_logger.LogWarning("Rate limiting circuit opened")
            },
                                                          onCircuitClosed: () =>
            {
                //logger.LogWarning("Rate limiting circuit closed")
            }),

                countThrottledRequests: true
                );

            #endregion

            var configSettings = new DomainElasticSearchLoggingOptions()
            {
                Enabled     = true,
                Url         = "http://localhost:9200",
                Application = "Public Adapter",
                IndexFormat = "quotaaudits-{0:yyyy.MM.dd}"
            };

            var loggerConfig = new LoggerConfiguration()
                               .MinimumLevel.Information()
                               .Enrich.FromLogContext();

            // if enabled in appsettings.json, logs will be shipped to Elasticsearch in a standard json format
            if (configSettings.Enabled)
            {
                loggerConfig.WriteTo.DomainElasticsearch(configSettings);
            }

            var auditLogger = loggerConfig.CreateLogger();

            var policyProvider = new ClientQuotaPolicyProvider();

            filters.Add(new RateLimitingFilter(

                            new RateLimiter(rateLimitCacheProvider, new RateLimitingPolicyManager(policyProvider)),

                            filters,

                            onPostLimit: async(request, policy, result, actionContext) =>
            {
                var operationClass = CallClassification.RouteTemplateToClassMap[request.RouteTemplate];
                var cost           = CallClassification.CostPerClass[operationClass];

                var clientId = result.CacheKey.RequestId;
                // sns publish

                if (result.State == ResultState.Success)
                {
                    // sns publish
                    auditLogger.Information(
                        "Result {Result}: Request success for client {ClientId} and endpoint {Endpoint} with route {RouteTemplate} which is Class {Class} with Cost {Cost}",
                        "Success",
                        clientId,
                        request.Path,
                        request.RouteTemplate,
                        operationClass,
                        cost);
                }
                else if (result.State == ResultState.Throttled)
                {
                    auditLogger.Information(
                        "Result {Result}: throttled for client {ClientId} and endpoint {Endpoint} with route {RouteTemplate} which is Class {Class} with Cost {Cost} by violating policy {ViolatedPolicy}",
                        "Throttled",
                        clientId,
                        request.Path,
                        request.RouteTemplate,
                        operationClass,
                        cost,
                        $"{policy.Name}:{result.CacheKey.AllowedConsumptionRate}");
                }
                else if (result.State == ResultState.ThrottledButCompensationFailed)
                {
                    auditLogger.Information(
                        "Result {Result}: throttled but failed to compensate for client {ClientId} and endpoint {Endpoint} with route {RouteTemplate} which is Class {Class} with Cost {Cost} by violating policy {ViolatedPolicy}",
                        result.State,
                        clientId,
                        request.Path,
                        request.RouteTemplate,
                        operationClass,
                        cost,
                        $"{policy.Name}:{result.CacheKey.AllowedConsumptionRate}");
                }
                else if (result.State == ResultState.LimitApplicationFailed)
                {
                    auditLogger.Information(
                        "Result {Result}: Free pass for client {ClientId} and endpoint {Endpoint} with route {RouteTemplate} which is Class {Class} with Cost {Cost}",
                        "FreePass",
                        clientId,
                        request.Path,
                        request.RouteTemplate,
                        operationClass,
                        cost);
                }
                else if (result.State == ResultState.NotApplicable)
                {
                    auditLogger.Information(
                        "Result {Result}: Not Applicable for client {ClientId} and endpoint {Endpoint} with route {RouteTemplate} which is Class {Class} with Cost {Cost}",
                        ResultState.NotApplicable,
                        clientId,
                        request.Path,
                        request.RouteTemplate,
                        operationClass,
                        cost);
                }


                return(Decision.OK);
            },

                            onPostLimitRevert: async(request, policy, result, actionContext) =>
            {
                var operationClass = CallClassification.RouteTemplateToClassMap[request.RouteTemplate];

                if (result.State == ResultState.Success || result.State == ResultState.Throttled)
                {
                    auditLogger.Information(
                        "Result {Result}: Limit Cost Reverted for client {ClientId} and endpoint {Endpoint} with route {RouteTemplate} which is Class {Class} with Cost {Cost}",
                        "SuccessCostReverted",
                        result.CacheKey.RequestId,
                        request.Path,
                        request.RouteTemplate,
                        operationClass,
                        -policy.CostPerCall);
                }
                else if (result.State == ResultState.LimitApplicationFailed)
                {
                    auditLogger.Information(
                        "Result {Result}: Limit Cost Reverting failed for client {ClientId} and endpoint {Endpoint} with route {RouteTemplate} which is Class {Class} with Cost {Cost}",
                        "SuccessCostRevertingFailed",
                        result.CacheKey.RequestId,
                        request.Path,
                        request.RouteTemplate,
                        operationClass,
                        -policy.CostPerCall);
                }
            },

                            postOperationDecisionFuncAsync: async(request, policy, result, actionExecutedContext) =>
            {
                if (actionExecutedContext.Exception != null || (int)actionExecutedContext.Response.StatusCode >= 400)
                {
                    return(Decision.REVERTSUCCESSCOST);
                }

                return(Decision.OK);
            },

                            //getPolicyFuncAsync: policyProvider.GetPolicyAsync,
                            simulationMode: false));
        }
Example #4
0
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            // Adds services required for using options.
            services.AddOptions();

            #region Setting policies explicitly using code

            var rateLimitingPolicyParametersProvider  = new SampleRateLimitingClientPolicyProvider();
            var globalRateLimitingClientPolicyManager =
                new RateLimitingPolicyManager(rateLimitingPolicyParametersProvider)
                .AddPathToWhiteList("/api/unlimited")
                .AddPoliciesForAllEndpoints(new List <AllowedConsumptionRate>()
            {
                new AllowedConsumptionRate(1000, RateLimitUnit.PerMinute)
            }, allowAttributeOverride: true, name: "StaticPolicy_2")
                .AddEndpointPolicy("/api/globallylimited/{id}", "GET", new List <AllowedConsumptionRate>()
            {
                new AllowedConsumptionRate(5, RateLimitUnit.PerMinute),
                new AllowedConsumptionRate(8, RateLimitUnit.PerHour)
            }, true, "StaticPolicy_0")
                .AddEndpointPolicy("/api/globallylimited/{id}/sub/{subid}", RateLimitPolicy.AllHttpMethods,
                                   new List <AllowedConsumptionRate>()
            {
                new AllowedConsumptionRate(2, RateLimitUnit.PerMinute)
            }, true, "StaticPolicy_1");

            #endregion

            #region Setting Policies Using Configuration Options
            // var rateLimitingOptions = new RateLimitingOptions();
            // Configuration.GetSection(nameof(RateLimitingOptions)).Bind(rateLimitingOptions);

            // var globalRateLimitingClientPolicyManager = new RateLimitingPolicyManager(
            //        new SampleRateLimitingClientPolicyProvider())
            //    .AddPoliciesForAllEndpoints(new List<AllowedCallRate>() {new AllowedCallRate(180, RateLimitUnit.PerMinute)},name:"ClientPolicy")
            //    .AddPathsToWhiteList(rateLimitingOptions.RateLimitingWhiteListedPaths)
            //    .AddRequestKeysToWhiteList(rateLimitingOptions.RateLimitingWhiteListedRequestKeys);
            #endregion

            #region Setting up the Redis rate limiter
            var redisRateLimiterSettings = new RedisRateLimiterSettings();
            Configuration.GetSection(nameof(RedisRateLimiterSettings)).Bind(redisRateLimiterSettings);

            var rateLimitCacheProvider = new SlidingTimeWindowRateLimiter(
                redisRateLimiterSettings.RateLimitRedisCacheConnectionString,
                (exp) => _logger.LogError("Error in rate limiting",
                                          exp),
                onThrottled: (rateLimitingResult) =>
            {
                _logger.LogInformation(
                    "Request throttled for client {ClientId} and endpoint {Endpoint}",
                    rateLimitingResult.CacheKey.RequestId,
                    rateLimitingResult.CacheKey.RouteTemplate);
            },
                circuitBreaker: new DefaultCircuitBreaker(redisRateLimiterSettings.FaultThreshholdPerWindowDuration,
                                                          redisRateLimiterSettings.FaultWindowDurationInMilliseconds, redisRateLimiterSettings.CircuitOpenIntervalInSecs,
                                                          onCircuitOpened: () => _logger.LogWarning("Rate limiting circuit opened"),
                                                          onCircuitClosed: () => _logger.LogWarning("Rate limiting circuit closed")));

            #endregion


            // Add framework services
            services.AddMvc(options =>
            {
                #region Adding the RateLimitingFilter
                options.Filters.Add(new RateLimitingFilter(
                                        new RateLimiter(rateLimitCacheProvider, globalRateLimitingClientPolicyManager)));
                #endregion

                #region Multi level rate limiting - Multiple action filters based on separate Policy Providers providing separate policies
                //options.Filters.Add(new RateLimitingFilter(
                //    new RateLimiter(rateLimitCacheProvider, new SampleRateLimitingUserPolicyProvider())));
                //options.Filters.Add(new RateLimitingFilter(
                //    new RateLimiter(rateLimitCacheProvider, new SampleRateLimitingOrganizationPolicyProvider())));
                #endregion
            });
        }