private bool IsRequestForbidden(HttpContext context)
        {
            // lock to synchronise the multiple calls on web apis.
            lock (_syncLock)
            {
                // read api limit rules from config or by default limit rules
                var apiLimitRuleDetails = GetApiLimitRuleDetails(context);

                // throttle cache is present means service threshold is reached, need to suspend the request.
                if (_cache.Get(GetThrottleBaseKey(apiLimitRuleDetails.EndPointKey)) != null)
                {
                    return(true);
                }
                if (!_cache.TryGetValue(apiLimitRuleDetails.EndPointKey, out CacheSetting serviceHitCounter))
                {
                    // create service hit counter with 1
                    CreateOrUpdateCache(apiLimitRuleDetails.EndPointKey, _cacheSettingProvider.CreateCacheSetting(apiLimitRuleDetails.Period));
                    return(false);
                }
                // as long as threshold is not reached just increment the counter and update the service cache counter
                if (serviceHitCounter.Value < apiLimitRuleDetails.Limit)
                {
                    serviceHitCounter.Value++;
                    CreateOrUpdateCache(apiLimitRuleDetails.EndPointKey, serviceHitCounter);
                    return(false);
                }
                // api limit threshold is reached, need to add throttle cache in the memory to suspend subsequent calls to api for particular duration
                CreateOrUpdateCache(GetThrottleBaseKey(apiLimitRuleDetails.EndPointKey), _cacheSettingProvider.CreateCacheSetting(apiLimitRuleDetails.SuspendPeriod));
                return(true);
            }
        }
Exemple #2
0
        public async Task Invoke(HttpContext context)
        {
            if (IsRateLimitRequestRequired())
            {
                _logger.LogWarning(LoggingMessages.Forbidden + context.User);

                // waiting for 3 seconds to serve the request.
                await semaphoreSlim.WaitAsync();

                try
                {
                    await Task.Delay(3000);
                }
                finally
                {
                    semaphoreSlim.Release();
                }

                // reset to one as we wait for 3 seconds.
                CreateOrUpdateCache("RequestCount", _cacheSettingProvider.CreateCacheSetting(int.MaxValue));
            }
            await _next.Invoke(context);
        }
Exemple #3
0
        public async Task <IEnumerable <ProductViewModel> > SearchFoodProducts(ProductSearchInput input)
        {
            string url = _httpQueryBuilder.Build(input);

            var request = new HttpRequestMessage(HttpMethod.Get, url);

            // create http client for downloading the food products
            var client = _clientFactory.CreateClient();

            // timeout 20 seconds
            client.Timeout = TimeSpan.FromSeconds(20);

            try
            {
                var response = await client.SendAsync(request);

                if (!response.IsSuccessStatusCode)
                {
                    return(Enumerable.Empty <ProductViewModel>());
                }

                var responseStream = await response.Content.ReadAsStringAsync();

                var productDetails = JsonSerializer.Deserialize <FoodProductModel>(responseStream);

                // validate if the product details is null or 0 or no products
                if (!IsValid(productDetails))
                {
                    return(Enumerable.Empty <ProductViewModel>());
                }

                if (!_cache.TryGetValue("PaginationCount", out CacheSetting paginationCounter))
                {
                    // create service hit pagination counter with 1
                    CreateOrUpdateCache("PaginationCount", _cacheSettingProvider.CreateCacheSetting(int.MaxValue, 0));

                    paginationCounter = _cache.Get <CacheSetting>("PaginationCount");
                }

                // this condition to reset the counter as we reached the end of food products.
                if (productDetails.Products.Length < paginationCounter.Value)
                {
                    paginationCounter.Value = 0;
                }

                // skipping the already served foo products & taking only 5
                var foodToReturn = productDetails.Products.Skip(paginationCounter.Value).Take(5);

                // increment the pagination counter by 5
                paginationCounter.Value += 5;

                // updating the counter value
                CreateOrUpdateCache("PaginationCount", paginationCounter);

                return(_mapper.Map <List <ProductViewModel> >(foodToReturn));
            }
            catch (Exception ex)
            {
                //todo third party api is taking too much time.
                _logger.LogError(ex.Message, request);
            }
            return(Enumerable.Empty <ProductViewModel>());
        }