mirror of
				https://github.com/nsnail/Ocelot.git
				synced 2025-11-04 09:15:27 +08:00 
			
		
		
		
	added docs but qos acceptance test not working seems circuit never opens but not sure if it is meant to with timeouts..investigating
This commit is contained in:
		
							
								
								
									
										40
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										40
									
								
								README.md
									
									
									
									
									
								
							@@ -305,19 +305,25 @@ Below is an example configuration that will transforms claims to query string pa
 | 
				
			|||||||
This shows a transform where Ocelot looks at the users LocationId claim and add its as
 | 
					This shows a transform where Ocelot looks at the users LocationId claim and add its as
 | 
				
			||||||
a query string parameter to be forwarded onto the downstream service.
 | 
					a query string parameter to be forwarded onto the downstream service.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Logging
 | 
					## Quality of Service
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Ocelot uses the standard logging interfaces ILoggerFactory / ILogger<T> at the moment. 
 | 
					Ocelot supports one QoS capability at the current time. You can set on a per ReRoute basis if you 
 | 
				
			||||||
This is encapsulated in  IOcelotLogger / IOcelotLoggerFactory with an implementation 
 | 
					want to use a circuit breaker when making requests to a downstream service. This uses the an awesome
 | 
				
			||||||
for the standard asp.net core logging stuff at the moment. 
 | 
					.NET library called Polly check them out [here](https://github.com/App-vNext/Polly).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
There are a bunch of debugging logs in the ocelot middlewares however I think the 
 | 
					Add the following section to a ReRoute configuration. 
 | 
				
			||||||
system probably needs more logging in the code it calls into. Other than the debugging
 | 
					 | 
				
			||||||
there is a global error handler that should catch any errors thrown and log them as errors.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
The reason for not just using bog standard framework logging is that I could not 
 | 
							"QoSOptions": {
 | 
				
			||||||
work out how to override the request id that get's logged when setting IncludeScopes 
 | 
								"ExceptionsAllowedBeforeBreaking":3,
 | 
				
			||||||
to true for logging settings. Nicely onto the next feature.
 | 
								"DurationOfBreak":5,
 | 
				
			||||||
 | 
								"TimeoutValue":5000
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You must set a number greater than 0 against ExceptionsAllowedBeforeBreaking for this rule to be 
 | 
				
			||||||
 | 
					implemented. Duration of break is how long the circuit breaker will stay open for after it is tripped.
 | 
				
			||||||
 | 
					TimeoutValue means ff a request takes more than 5 seconds it will automatically be timed out. 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If you do not add a QoS section QoS will not be used.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## RequestId / CorrelationId
 | 
					## RequestId / CorrelationId
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -404,6 +410,20 @@ http request before it is passed to Ocelots request creator.
 | 
				
			|||||||
Obviously you can just add middleware as normal before the call to app.UseOcelot() It cannot be added
 | 
					Obviously you can just add middleware as normal before the call to app.UseOcelot() It cannot be added
 | 
				
			||||||
after as Ocelot does not call the next middleware.
 | 
					after as Ocelot does not call the next middleware.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Logging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Ocelot uses the standard logging interfaces ILoggerFactory / ILogger<T> at the moment. 
 | 
				
			||||||
 | 
					This is encapsulated in  IOcelotLogger / IOcelotLoggerFactory with an implementation 
 | 
				
			||||||
 | 
					for the standard asp.net core logging stuff at the moment. 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					There are a bunch of debugging logs in the ocelot middlewares however I think the 
 | 
				
			||||||
 | 
					system probably needs more logging in the code it calls into. Other than the debugging
 | 
				
			||||||
 | 
					there is a global error handler that should catch any errors thrown and log them as errors.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The reason for not just using bog standard framework logging is that I could not 
 | 
				
			||||||
 | 
					work out how to override the request id that get's logged when setting IncludeScopes 
 | 
				
			||||||
 | 
					to true for logging settings. Nicely onto the next feature.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Not supported
 | 
					## Not supported
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Ocelot does not support...
 | 
					Ocelot does not support...
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,7 +8,11 @@ namespace Ocelot.Configuration
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    public class QoSOptions
 | 
					    public class QoSOptions
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        public QoSOptions(int exceptionsAllowedBeforeBreaking, int durationofBreak, int timeoutValue, TimeoutStrategy timeoutStrategy = TimeoutStrategy.Pessimistic)
 | 
					        public QoSOptions(
 | 
				
			||||||
 | 
					            int exceptionsAllowedBeforeBreaking, 
 | 
				
			||||||
 | 
					            int durationofBreak, 
 | 
				
			||||||
 | 
					            int timeoutValue, 
 | 
				
			||||||
 | 
					            TimeoutStrategy timeoutStrategy = TimeoutStrategy.Pessimistic)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            ExceptionsAllowedBeforeBreaking = exceptionsAllowedBeforeBreaking;
 | 
					            ExceptionsAllowedBeforeBreaking = exceptionsAllowedBeforeBreaking;
 | 
				
			||||||
            DurationOfBreak = TimeSpan.FromMilliseconds(durationofBreak);
 | 
					            DurationOfBreak = TimeSpan.FromMilliseconds(durationofBreak);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,6 +25,7 @@
 | 
				
			|||||||
        ServicesAreNullError,
 | 
					        ServicesAreNullError,
 | 
				
			||||||
        ServicesAreEmptyError,
 | 
					        ServicesAreEmptyError,
 | 
				
			||||||
        UnableToFindServiceDiscoveryProviderError,
 | 
					        UnableToFindServiceDiscoveryProviderError,
 | 
				
			||||||
        UnableToFindLoadBalancerError
 | 
					        UnableToFindLoadBalancerError,
 | 
				
			||||||
 | 
					        RequestTimedOutError
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,11 +18,17 @@ namespace Ocelot.Requester
 | 
				
			|||||||
        private readonly Policy _circuitBreakerPolicy;
 | 
					        private readonly Policy _circuitBreakerPolicy;
 | 
				
			||||||
        private readonly TimeoutPolicy _timeoutPolicy;
 | 
					        private readonly TimeoutPolicy _timeoutPolicy;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public CircuitBreakingDelegatingHandler(int exceptionsAllowedBeforeBreaking, TimeSpan durationOfBreak,TimeSpan timeoutValue
 | 
					        public CircuitBreakingDelegatingHandler(
 | 
				
			||||||
            ,TimeoutStrategy timeoutStrategy, IOcelotLogger logger, HttpMessageHandler innerHandler)
 | 
					            int exceptionsAllowedBeforeBreaking, 
 | 
				
			||||||
 | 
					            TimeSpan durationOfBreak,
 | 
				
			||||||
 | 
					            TimeSpan timeoutValue,
 | 
				
			||||||
 | 
					            TimeoutStrategy timeoutStrategy, 
 | 
				
			||||||
 | 
					            IOcelotLogger logger, 
 | 
				
			||||||
 | 
					            HttpMessageHandler innerHandler)
 | 
				
			||||||
            : base(innerHandler)
 | 
					            : base(innerHandler)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            this._exceptionsAllowedBeforeBreaking = exceptionsAllowedBeforeBreaking;
 | 
					            this._exceptionsAllowedBeforeBreaking = exceptionsAllowedBeforeBreaking;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this._durationOfBreak = durationOfBreak;
 | 
					            this._durationOfBreak = durationOfBreak;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            _circuitBreakerPolicy = Policy
 | 
					            _circuitBreakerPolicy = Policy
 | 
				
			||||||
@@ -39,30 +45,27 @@ namespace Ocelot.Requester
 | 
				
			|||||||
                    onReset: () => _logger.LogDebug(".Breaker logging: Call ok! Closed the circuit again."),
 | 
					                    onReset: () => _logger.LogDebug(".Breaker logging: Call ok! Closed the circuit again."),
 | 
				
			||||||
                    onHalfOpen: () => _logger.LogDebug(".Breaker logging: Half-open; next call is a trial.")
 | 
					                    onHalfOpen: () => _logger.LogDebug(".Breaker logging: Half-open; next call is a trial.")
 | 
				
			||||||
                    );
 | 
					                    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            _timeoutPolicy = Policy.TimeoutAsync(timeoutValue, timeoutStrategy);
 | 
					            _timeoutPolicy = Policy.TimeoutAsync(timeoutValue, timeoutStrategy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            _logger = logger;
 | 
					            _logger = logger;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
 | 
					        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Task<HttpResponseMessage> responseTask = null;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            try
 | 
					            try
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                responseTask = Policy.WrapAsync(_circuitBreakerPolicy, _timeoutPolicy).ExecuteAsync<HttpResponseMessage>(() =>
 | 
					                return await Policy.WrapAsync(_circuitBreakerPolicy, _timeoutPolicy).ExecuteAsync(() => base.SendAsync(request,cancellationToken));
 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    return  base.SendAsync(request,cancellationToken);
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
                return responseTask;
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            catch (BrokenCircuitException ex)
 | 
					            catch (BrokenCircuitException ex)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                _logger.LogError($"Reached to allowed number of exceptions. Circuit is open. AllowedExceptionCount: {_exceptionsAllowedBeforeBreaking}, DurationOfBreak: {_durationOfBreak}",ex);
 | 
					                _logger.LogError($"Reached to allowed number of exceptions. Circuit is open. AllowedExceptionCount: {_exceptionsAllowedBeforeBreaking}, DurationOfBreak: {_durationOfBreak}",ex);
 | 
				
			||||||
                throw;
 | 
					                throw;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            catch (HttpRequestException)
 | 
					            catch (HttpRequestException ex)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                return responseTask;
 | 
					                _logger.LogError($"Error in CircuitBreakingDelegatingHandler.SendAync", ex);
 | 
				
			||||||
 | 
					                throw;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,6 +27,7 @@ namespace Ocelot.Requester
 | 
				
			|||||||
                {
 | 
					                {
 | 
				
			||||||
                    builder.WithCircuitBreaker(request.Qos, _logger, handler);
 | 
					                    builder.WithCircuitBreaker(request.Qos, _logger, handler);
 | 
				
			||||||
                }           
 | 
					                }           
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                using (var httpClient = builder.Build(handler))
 | 
					                using (var httpClient = builder.Build(handler))
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    try
 | 
					                    try
 | 
				
			||||||
@@ -34,13 +35,14 @@ namespace Ocelot.Requester
 | 
				
			|||||||
                        var response = await httpClient.SendAsync(request.HttpRequestMessage);
 | 
					                        var response = await httpClient.SendAsync(request.HttpRequestMessage);
 | 
				
			||||||
                        return new OkResponse<HttpResponseMessage>(response);
 | 
					                        return new OkResponse<HttpResponseMessage>(response);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    catch (Exception exception)
 | 
					                    catch (Polly.Timeout.TimeoutRejectedException exception)
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        return
 | 
					                        return
 | 
				
			||||||
                            new ErrorResponse<HttpResponseMessage>(new List<Error>
 | 
					                           new ErrorResponse<HttpResponseMessage>(new RequestTimedOutError(exception));
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    catch (Exception exception)
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                                new UnableToCompleteRequestError(exception)
 | 
					                        return new ErrorResponse<HttpResponseMessage>(new UnableToCompleteRequestError(exception));
 | 
				
			||||||
                            });
 | 
					 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										13
									
								
								src/Ocelot/Requester/RequestTimedOutError.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/Ocelot/Requester/RequestTimedOutError.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using Ocelot.Errors;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ocelot.Requester
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class RequestTimedOutError : Error
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public RequestTimedOutError(Exception exception) 
 | 
				
			||||||
 | 
					            : base($"Timeout making http request, exception: {exception.Message}", OcelotErrorCode.RequestTimedOutError)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -22,6 +22,11 @@ namespace Ocelot.Responder
 | 
				
			|||||||
                return new OkResponse<int>(403);
 | 
					                return new OkResponse<int>(403);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (errors.Any(e => e.Code == OcelotErrorCode.RequestTimedOutError))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return new OkResponse<int>(408);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return new OkResponse<int>(404);
 | 
					            return new OkResponse<int>(404);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,7 +5,13 @@ namespace Ocelot.Responses
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    public class ErrorResponse<T> : Response<T>
 | 
					    public class ErrorResponse<T> : Response<T>
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        public ErrorResponse(List<Error> errors) : base(errors)
 | 
					        public ErrorResponse(Error error) 
 | 
				
			||||||
 | 
					            : base(new List<Error> {error})
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public ErrorResponse(List<Error> errors) 
 | 
				
			||||||
 | 
					            : base(errors)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										136
									
								
								test/Ocelot.AcceptanceTests/QoSTests.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								test/Ocelot.AcceptanceTests/QoSTests.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,136 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.IO;
 | 
				
			||||||
 | 
					using System.Net;
 | 
				
			||||||
 | 
					using System.Threading;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					using Microsoft.AspNetCore.Builder;
 | 
				
			||||||
 | 
					using Microsoft.AspNetCore.Hosting;
 | 
				
			||||||
 | 
					using Microsoft.AspNetCore.Http;
 | 
				
			||||||
 | 
					using Ocelot.Configuration.File;
 | 
				
			||||||
 | 
					using TestStack.BDDfy;
 | 
				
			||||||
 | 
					using Xunit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ocelot.AcceptanceTests
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class QoSTests : IDisposable
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        private IWebHost _builder;
 | 
				
			||||||
 | 
					        private readonly Steps _steps;
 | 
				
			||||||
 | 
					        private int _requestCount;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public QoSTests()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _steps = new Steps();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_open_circuit_breaker_then_close()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var configuration = new FileConfiguration
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                ReRoutes = new List<FileReRoute>
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    new FileReRoute
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        DownstreamPathTemplate = "/",
 | 
				
			||||||
 | 
					                        DownstreamScheme = "http",
 | 
				
			||||||
 | 
					                        DownstreamHost = "localhost",
 | 
				
			||||||
 | 
					                        DownstreamPort = 51879,
 | 
				
			||||||
 | 
					                        UpstreamPathTemplate = "/",
 | 
				
			||||||
 | 
					                        UpstreamHttpMethod = "Get",
 | 
				
			||||||
 | 
					                        QoSOptions = new FileQoSOptions
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            ExceptionsAllowedBeforeBreaking = 1,
 | 
				
			||||||
 | 
					                            TimeoutValue = 500,
 | 
				
			||||||
 | 
					                            DurationOfBreak = 1000
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", "Hello from Laura"))
 | 
				
			||||||
 | 
					                .Given(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
				
			||||||
 | 
					                .Given(x => _steps.GivenOcelotIsRunning())
 | 
				
			||||||
 | 
					                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
				
			||||||
 | 
					                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
				
			||||||
 | 
					                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
				
			||||||
 | 
					                .Given(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
				
			||||||
 | 
					                .Given(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.RequestTimeout))
 | 
				
			||||||
 | 
					                .Given(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
				
			||||||
 | 
					                .Given(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.RequestTimeout))
 | 
				
			||||||
 | 
					                .Given(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
				
			||||||
 | 
					                .Given(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.RequestTimeout))
 | 
				
			||||||
 | 
					                .Given(x => x.GivenIWaitMilliSeconds(2000))
 | 
				
			||||||
 | 
					                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
				
			||||||
 | 
					                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
				
			||||||
 | 
					                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void GivenIWaitMilliSeconds(int ms)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Thread.Sleep(ms);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void GivenThereIsAServiceRunningOn(string url, string responseBody)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _builder = new WebHostBuilder()
 | 
				
			||||||
 | 
					                .UseUrls(url)
 | 
				
			||||||
 | 
					                .UseKestrel()
 | 
				
			||||||
 | 
					                .UseContentRoot(Directory.GetCurrentDirectory())
 | 
				
			||||||
 | 
					                .UseIISIntegration()
 | 
				
			||||||
 | 
					                .UseUrls(url)
 | 
				
			||||||
 | 
					                .Configure(app =>
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    app.Run(async context =>
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        //circuit starts closed
 | 
				
			||||||
 | 
					                        if (_requestCount == 0)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            _requestCount++;
 | 
				
			||||||
 | 
					                            context.Response.StatusCode = 200;
 | 
				
			||||||
 | 
					                            await context.Response.WriteAsync(responseBody);
 | 
				
			||||||
 | 
					                            return;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        //request one times out and polly throws exception
 | 
				
			||||||
 | 
					                        if (_requestCount == 1)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            _requestCount++;
 | 
				
			||||||
 | 
					                            await Task.Delay(1000);
 | 
				
			||||||
 | 
					                            context.Response.StatusCode = 200;
 | 
				
			||||||
 | 
					                            return;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        //request two times out and polly throws exception circuit opens
 | 
				
			||||||
 | 
					                        if (_requestCount == 2)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            _requestCount++;
 | 
				
			||||||
 | 
					                            await Task.Delay(1000);
 | 
				
			||||||
 | 
					                            context.Response.StatusCode = 200;
 | 
				
			||||||
 | 
					                            return;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        //after break closes we return 200 OK
 | 
				
			||||||
 | 
					                        if (_requestCount == 3)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            context.Response.StatusCode = 200;
 | 
				
			||||||
 | 
					                            await context.Response.WriteAsync(responseBody);
 | 
				
			||||||
 | 
					                            return;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            _builder.Start();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public void Dispose()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _builder?.Dispose();
 | 
				
			||||||
 | 
					            _steps.Dispose();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,6 +1,8 @@
 | 
				
			|||||||
using System.Collections.Generic;
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using Ocelot.Errors;
 | 
					using Ocelot.Errors;
 | 
				
			||||||
using Ocelot.Middleware;
 | 
					using Ocelot.Middleware;
 | 
				
			||||||
 | 
					using Ocelot.Requester;
 | 
				
			||||||
using Ocelot.Responder;
 | 
					using Ocelot.Responder;
 | 
				
			||||||
using Ocelot.Responses;
 | 
					using Ocelot.Responses;
 | 
				
			||||||
using Shouldly;
 | 
					using Shouldly;
 | 
				
			||||||
@@ -20,6 +22,18 @@ namespace Ocelot.UnitTests.Responder
 | 
				
			|||||||
            _codeMapper = new ErrorsToHttpStatusCodeMapper();
 | 
					            _codeMapper = new ErrorsToHttpStatusCodeMapper();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_return_timeout()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            this.Given(x => x.GivenThereAreErrors(new List<Error>
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    new RequestTimedOutError(new Exception())
 | 
				
			||||||
 | 
					                }))
 | 
				
			||||||
 | 
					               .When(x => x.WhenIGetErrorStatusCode())
 | 
				
			||||||
 | 
					               .Then(x => x.ThenTheResponseIsStatusCodeIs(408))
 | 
				
			||||||
 | 
					               .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void should_create_unauthenticated_response_code()
 | 
					        public void should_create_unauthenticated_response_code()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user