From b6a907f9ac2040e39ba953c4e729168ec2572021 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Raynald=20Messi=C3=A9?= Date: Wed, 29 May 2024 16:04:46 +0200 Subject: [PATCH] #2080 Adds parameters (in this case those of Polly V8) to fine-tune circuit-breaker behavior --- .../PollyQoSResiliencePipelineProvider.cs | 5 +- src/Ocelot/Configuration/QoSOptions.cs | 48 ++++++++++++++++++- test/Ocelot.AcceptanceTests/PollyQoSTests.cs | 4 +- 3 files changed, 52 insertions(+), 5 deletions(-) diff --git a/src/Ocelot.Provider.Polly/PollyQoSResiliencePipelineProvider.cs b/src/Ocelot.Provider.Polly/PollyQoSResiliencePipelineProvider.cs index 6ec9b5d53..0a2f66942 100644 --- a/src/Ocelot.Provider.Polly/PollyQoSResiliencePipelineProvider.cs +++ b/src/Ocelot.Provider.Polly/PollyQoSResiliencePipelineProvider.cs @@ -4,6 +4,7 @@ using Polly.CircuitBreaker; using Polly.Registry; using Polly.Timeout; +using System; using System.Net; namespace Ocelot.Provider.Polly; @@ -76,8 +77,8 @@ protected virtual ResiliencePipelineBuilder ConfigureCircui var info = $"Circuit Breaker for the route: {GetRouteName(route)}: "; var strategyOptions = new CircuitBreakerStrategyOptions { - FailureRatio = 0.8, - SamplingDuration = TimeSpan.FromSeconds(10), + FailureRatio = options.FailureRatio, + SamplingDuration = TimeSpan.FromMilliseconds(options.SamplingDuration), MinimumThroughput = options.ExceptionsAllowedBeforeBreaking, BreakDuration = options.DurationOfBreak > QoSOptions.LowBreakDuration ? TimeSpan.FromMilliseconds(options.DurationOfBreak) diff --git a/src/Ocelot/Configuration/QoSOptions.cs b/src/Ocelot/Configuration/QoSOptions.cs index 071bfbf95..c36ce6cf6 100644 --- a/src/Ocelot/Configuration/QoSOptions.cs +++ b/src/Ocelot/Configuration/QoSOptions.cs @@ -23,7 +23,7 @@ public QoSOptions(FileQoSOptions from) public QoSOptions( int exceptionsAllowedBeforeBreaking, int durationOfBreak, - int timeoutValue, + int timeoutValue, string key) { DurationOfBreak = durationOfBreak; @@ -32,6 +32,36 @@ public QoSOptions( TimeoutValue = timeoutValue; } + public QoSOptions( + int exceptionsAllowedBeforeBreaking, + int durationOfBreak, + double failureRatio, + int timeoutValue, + string key) + { + DurationOfBreak = durationOfBreak; + ExceptionsAllowedBeforeBreaking = exceptionsAllowedBeforeBreaking; + Key = key; + TimeoutValue = timeoutValue; + FailureRatio = failureRatio; + } + + public QoSOptions( + int exceptionsAllowedBeforeBreaking, + int durationOfBreak, + double failureRatio, + int samplingDuration, + int timeoutValue, + string key) + { + DurationOfBreak = durationOfBreak; + ExceptionsAllowedBeforeBreaking = exceptionsAllowedBeforeBreaking; + Key = key; + TimeoutValue = timeoutValue; + FailureRatio = failureRatio; + SamplingDuration = samplingDuration; + } + /// How long the circuit should stay open before resetting in milliseconds. /// If using Polly version 8 or above, this value must be 500 (0.5 sec) or greater. /// An value (milliseconds). @@ -50,6 +80,22 @@ public QoSOptions( /// public int ExceptionsAllowedBeforeBreaking { get; } + /// + /// The failure-success ratio that will cause the circuit to break/open. + /// + /// + /// An 0.8 means 80% failed of all sampled executions. + /// + public double FailureRatio { get; } = .8; + + /// + /// The time period over which the failure-success ratio is calculated (in seconds). + /// + /// + /// An Time period in seconds, 10 means 10 seconds. + /// + public int SamplingDuration { get; } = 10; + public string Key { get; } /// diff --git a/test/Ocelot.AcceptanceTests/PollyQoSTests.cs b/test/Ocelot.AcceptanceTests/PollyQoSTests.cs index 5a086019a..8edd816d8 100644 --- a/test/Ocelot.AcceptanceTests/PollyQoSTests.cs +++ b/test/Ocelot.AcceptanceTests/PollyQoSTests.cs @@ -38,7 +38,7 @@ public override void Dispose() public void Should_not_timeout() { var port = PortFinder.GetRandomPort(); - var route = GivenRoute(port, new QoSOptions(10, 500, 1000, null), HttpMethods.Post); + var route = GivenRoute(port, new QoSOptions(10, 500, .5, 5, 1000, null), HttpMethods.Post); var configuration = GivenConfiguration(route); this.Given(x => x.GivenThereIsAServiceRunningOn(port, HttpStatusCode.OK, string.Empty, 10)) @@ -186,7 +186,7 @@ public void Should_timeout_per_default_after_90_seconds() var port = PortFinder.GetRandomPort(); var route = GivenRoute(port, new QoSOptions(new FileQoSOptions()), HttpMethods.Get); var configuration = GivenConfiguration(route); - + this.Given(x => x.GivenThereIsAServiceRunningOn(port, HttpStatusCode.Created, string.Empty, 3500)) // 3.5s > 3s -> ServiceUnavailable .And(x => GivenThereIsAConfiguration(configuration)) .And(x => GivenOcelotIsRunningWithPolly())