Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#908 Quality of Service - Configuration #1279

Merged
merged 15 commits into from
Sep 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/Ocelot.Provider.Polly/Interfaces/IPollyQoSProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Ocelot.Provider.Polly.Interfaces;

public interface IPollyQoSProvider
{
CircuitBreaker CircuitBreaker { get; }
}
23 changes: 8 additions & 15 deletions src/Ocelot.Provider.Polly/OcelotBuilderExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,15 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;

using global::Polly.CircuitBreaker;
using global::Polly.Timeout;
using Microsoft.Extensions.DependencyInjection;
using Ocelot.Configuration;

using Ocelot.DependencyInjection;

using Ocelot.Errors;

using global::Polly.CircuitBreaker;
using global::Polly.Timeout;

using Ocelot.Logging;

using Microsoft.Extensions.DependencyInjection;

using Ocelot.Requester;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;

namespace Ocelot.Provider.Polly
{
Expand All @@ -33,7 +26,7 @@ public static IOcelotBuilder AddPolly(this IOcelotBuilder builder)

builder.Services.AddSingleton(errorMapping);

DelegatingHandler QosDelegatingHandlerDelegate(DownstreamRoute route, IOcelotLoggerFactory logger)
static DelegatingHandler QosDelegatingHandlerDelegate(DownstreamRoute route, IOcelotLoggerFactory logger)
{
return new PollyCircuitBreakingDelegatingHandler(new PollyQoSProvider(route, logger), logger);
}
Expand Down
30 changes: 19 additions & 11 deletions src/Ocelot.Provider.Polly/PollyCircuitBreakingDelegatingHandler.cs
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

using Ocelot.Logging;

using Ocelot.Provider.Polly.Interfaces;
using Polly;
using Polly.CircuitBreaker;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

namespace Ocelot.Provider.Polly
{
public class PollyCircuitBreakingDelegatingHandler : DelegatingHandler
{
private readonly PollyQoSProvider _qoSProvider;
private readonly IPollyQoSProvider _qoSProvider;
private readonly IOcelotLogger _logger;

public PollyCircuitBreakingDelegatingHandler(
PollyQoSProvider qoSProvider,
IPollyQoSProvider qoSProvider,
IOcelotLoggerFactory loggerFactory)
{
_qoSProvider = qoSProvider;
Expand All @@ -26,9 +26,17 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
{
try
{
return await Policy
.WrapAsync(_qoSProvider.CircuitBreaker.Policies)
.ExecuteAsync(() => base.SendAsync(request, cancellationToken));
var policies = _qoSProvider.CircuitBreaker.Policies;
if (!policies.Any())
{
return await base.SendAsync(request, cancellationToken);
}

IAsyncPolicy policy = policies.Length > 1
? Policy.WrapAsync(policies)
: policies[0];

return await policy.ExecuteAsync(() => base.SendAsync(request, cancellationToken));
}
catch (BrokenCircuitException ex)
{
Expand All @@ -37,7 +45,7 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
}
catch (HttpRequestException ex)
{
_logger.LogError("Error in CircuitBreakingDelegatingHandler.SendAync", ex);
_logger.LogError($"Error in {nameof(PollyCircuitBreakingDelegatingHandler)}.{nameof(SendAsync)}", ex);
throw;
}
}
Expand Down
21 changes: 13 additions & 8 deletions src/Ocelot.Provider.Polly/PollyQoSProvider.cs
Original file line number Diff line number Diff line change
@@ -1,27 +1,32 @@
using System;
using System.Net.Http;

using Ocelot.Configuration;

using global::Polly;
using global::Polly.CircuitBreaker;
using global::Polly.Timeout;

using Ocelot.Configuration;
using Ocelot.Logging;
using Ocelot.Provider.Polly.Interfaces;
using System;
using System.Net.Http;

namespace Ocelot.Provider.Polly
{
public class PollyQoSProvider
public class PollyQoSProvider : IPollyQoSProvider
{
private readonly AsyncCircuitBreakerPolicy _circuitBreakerPolicy;
private readonly AsyncTimeoutPolicy _timeoutPolicy;
private readonly IOcelotLogger _logger;

public PollyQoSProvider(AsyncCircuitBreakerPolicy circuitBreakerPolicy, AsyncTimeoutPolicy timeoutPolicy, IOcelotLogger logger)
{
_circuitBreakerPolicy = circuitBreakerPolicy;
_timeoutPolicy = timeoutPolicy;
_logger = logger;
}

public PollyQoSProvider(DownstreamRoute route, IOcelotLoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<PollyQoSProvider>();

Enum.TryParse(route.QosOptions.TimeoutStrategy, out TimeoutStrategy strategy);
_ = Enum.TryParse(route.QosOptions.TimeoutStrategy, out TimeoutStrategy strategy);

_timeoutPolicy = Policy.TimeoutAsync(TimeSpan.FromMilliseconds(route.QosOptions.TimeoutValue), strategy);

Expand Down
22 changes: 9 additions & 13 deletions test/Ocelot.AcceptanceTests/PollyQoSTests.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
using System;
using Microsoft.AspNetCore.Http;
using Ocelot.Configuration.File;
using System;
using System.Collections.Generic;
using System.Net;
using System.Threading;
using System.Threading.Tasks;

using Ocelot.Configuration.File;

using Microsoft.AspNetCore.Http;

using TestStack.BDDfy;

using Xunit;

namespace Ocelot.AcceptanceTests
Expand All @@ -27,7 +23,7 @@ public PollyQoSTests()
}

[Fact]
public void should_not_timeout()
public void Should_not_timeout()
{
var port = RandomPortFinder.GetRandomPort();

Expand Down Expand Up @@ -68,7 +64,7 @@ public void should_not_timeout()
}

[Fact]
public void should_timeout()
public void Should_timeout()
{
var port = RandomPortFinder.GetRandomPort();

Expand All @@ -93,7 +89,6 @@ public void should_timeout()
QoSOptions = new FileQoSOptions
{
TimeoutValue = 10,
ExceptionsAllowedBeforeBreaking = 10,
},
},
},
Expand All @@ -109,7 +104,7 @@ public void should_timeout()
}

[Fact]
public void should_open_circuit_breaker_then_close()
public void Should_open_circuit_breaker_then_close()
{
var port = RandomPortFinder.GetRandomPort();

Expand Down Expand Up @@ -161,7 +156,7 @@ public void should_open_circuit_breaker_then_close()
}

[Fact]
public void open_circuit_should_not_effect_different_route()
public void Open_circuit_should_not_effect_different_route()
{
var port1 = RandomPortFinder.GetRandomPort();
var port2 = RandomPortFinder.GetRandomPort();
Expand Down Expand Up @@ -281,7 +276,8 @@ private void GivenThereIsAServiceRunningOn(string url, int statusCode, string re
public void Dispose()
{
_serviceHandler?.Dispose();
_steps.Dispose();
_steps.Dispose();
GC.SuppressFinalize(this);
}
}
}
14 changes: 4 additions & 10 deletions test/Ocelot.UnitTests/Polly/OcelotBuilderExtensionsTests.cs
Original file line number Diff line number Diff line change
@@ -1,27 +1,21 @@
using System.IO;

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

using Moq;

using Ocelot.Configuration.Builder;
using Ocelot.DependencyInjection;
using Ocelot.Logging;
using Ocelot.Requester;

using Ocelot.Provider.Polly;

using Ocelot.Requester;
using Shouldly;

using System.IO;
using Xunit;

namespace Ocelot.UnitTests.Polly
{
public class OcelotBuilderExtensionsTests
{
[Fact]
public void should_build()
public void Should_build()
{
var loggerFactory = new Mock<IOcelotLoggerFactory>();
var services = new ServiceCollection();
Expand Down
Loading