/// <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); }
/// <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); }