/// <summary>
        /// This method is called before the method is executed to verify that the resource is available.
        /// </summary>
        /// <param name="actionContext">The action context.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>Async method.</returns>
        public override async Task OnActionExecutingAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
        {
            var ms = actionContext.ToMicroservice();

            ResourceStatus status = ms?.ResourceMonitor.ResourceStatusGet(mResourceProfileId);

            switch (status?.State ?? CircuitBreakerState.Closed)
            {
            case CircuitBreakerState.Closed:     //Closed: so keep executing
                break;

            case CircuitBreakerState.HalfOpen:    // Check the probability function to randomly let some messages through, this is based on a 0-100% filter.
                if (mRand.Next(0, 100) <= status.FilterPercentage)
                {
                    break;
                }
                actionContext.Response = GenerateRequest(status, actionContext.Request);
                return;

            case CircuitBreakerState.Open:     //Return a 429 error
                actionContext.Response = GenerateRequest(status, actionContext.Request);
                return;
            }

            await base.OnActionExecutingAsync(actionContext, cancellationToken);
        }
        private HttpResponseMessage GenerateRequest(ResourceStatus status, HttpRequestMessage request)
        {
            HttpResponseMessage response = request.CreateResponse((HttpStatusCode)429);

            if (mDiscloseStatusinHTTPResponse)
            {
                response.ReasonPhrase = $"Too many requests. Circuit breaker thrown for {mResourceProfileId} at {status.State} for {status.FilterPercentage}%";
            }
            else
            {
                response.ReasonPhrase = $"Too many requests.";
            }

            if (status.RetryInSeconds.HasValue)
            {
                response.Headers.Add("Retry-After", status.RetryInSeconds.Value.ToString());
            }

            return(response);
        }
Example #3
0
        /// <summary>
        /// This method converts the current statistics in to a status snapshot.
        /// </summary>
        /// <returns>The current status.</returns>
        public ResourceStatus ToResourceStatus()
        {
            var rs = new ResourceStatus()
            {
                Name = Name, FilterPercentage = (int)(RateLimitAdjustmentPercentage * 100)
            };

            if (rs.FilterPercentage == 0)
            {
                rs.State = CircuitBreakerState.Open;
            }
            else if (rs.FilterPercentage < 100)
            {
                rs.State = CircuitBreakerState.HalfOpen;
            }
            else
            {
                rs.State = CircuitBreakerState.Closed;
            }

            return(rs);
        }