Skip to content

Commit

Permalink
#1844 More open customization of Polly use (#1974)
Browse files Browse the repository at this point in the history
* #1844 More open customization of Polly use

* Update src/Ocelot.Provider.Polly/OcelotBuilderExtensions.cs

Co-authored-by: Raman Maksimchuk <dotnet044@gmail.com>

* #1844 More open customization of Polly use

* Update src/Ocelot.Provider.Polly/OcelotBuilderExtensions.cs

Co-authored-by: Raman Maksimchuk <dotnet044@gmail.com>

* fix compilation errors

* add xml doc

* More XML-docs

* remove new line separators

---------

Co-authored-by: Ray <rmessie@traceparts.com>
Co-authored-by: Raman Maksimchuk <dotnet044@gmail.com>
  • Loading branch information
3 people committed Feb 26, 2024
1 parent 108bede commit 0404c24
Showing 1 changed file with 114 additions and 43 deletions.
157 changes: 114 additions & 43 deletions src/Ocelot.Provider.Polly/OcelotBuilderExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,44 +1,115 @@
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Ocelot.Configuration;
using Ocelot.DependencyInjection;
using Ocelot.Errors;
using Ocelot.Errors.QoS;
using Ocelot.Logging;
using Ocelot.Provider.Polly.Interfaces;
using Ocelot.Requester;
using Polly.CircuitBreaker;
using Polly.Timeout;

namespace Ocelot.Provider.Polly;

public static class OcelotBuilderExtensions
{
public static IOcelotBuilder AddPolly<T>(this IOcelotBuilder builder,
QosDelegatingHandlerDelegate delegatingHandler,
Dictionary<Type, Func<Exception, Error>> errorMapping)
where T : class, IPollyQoSProvider<HttpResponseMessage>
{
builder.Services
.AddSingleton(errorMapping)
.AddSingleton<IPollyQoSProvider<HttpResponseMessage>, T>()
.AddSingleton(delegatingHandler);

return builder;
}

public static IOcelotBuilder AddPolly(this IOcelotBuilder builder)
{
var errorMapping = new Dictionary<Type, Func<Exception, Error>>
{
{ typeof(TaskCanceledException), e => new RequestTimedOutError(e) },
{ typeof(TimeoutRejectedException), e => new RequestTimedOutError(e) },
{ typeof(BrokenCircuitException), e => new RequestTimedOutError(e) },
{ typeof(BrokenCircuitException<HttpResponseMessage>), e => new RequestTimedOutError(e) },
};
return AddPolly<PollyQoSProvider>(builder, GetDelegatingHandler, errorMapping);
}

private static DelegatingHandler GetDelegatingHandler(DownstreamRoute route, IHttpContextAccessor contextAccessor, IOcelotLoggerFactory loggerFactory)
=> new PollyPoliciesDelegatingHandler(route, contextAccessor, loggerFactory);
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Ocelot.Configuration;
using Ocelot.DependencyInjection;
using Ocelot.Errors;
using Ocelot.Errors.QoS;
using Ocelot.Logging;
using Ocelot.Provider.Polly.Interfaces;
using Ocelot.Requester;
using Polly.CircuitBreaker;
using Polly.Timeout;

namespace Ocelot.Provider.Polly;

public static class OcelotBuilderExtensions
{
/// <summary>
/// Default mapping of Polly <see cref="Exception"/>s to <see cref="Error"/> objects.
/// </summary>
public static readonly Dictionary<Type, Func<Exception, Error>> DefaultErrorMapping = new Dictionary<Type, Func<Exception, Error>>
{
{typeof(TaskCanceledException), CreateRequestTimedOutError},
{typeof(TimeoutRejectedException), CreateRequestTimedOutError},
{typeof(BrokenCircuitException), CreateRequestTimedOutError},
{typeof(BrokenCircuitException<HttpResponseMessage>), CreateRequestTimedOutError},
};

private static Error CreateRequestTimedOutError(Exception e) => new RequestTimedOutError(e);

/// <summary>
/// Adds Polly QoS provider to Ocelot by custom delegate and with custom error mapping.
/// </summary>
/// <typeparam name="T">QoS provider to use (by default use <see cref="PollyQoSProvider"/>).</typeparam>
/// <param name="builder">Ocelot builder to extend.</param>
/// <param name="delegatingHandler">Your customized delegating handler (to manage QoS behavior by yourself).</param>
/// <param name="errorMapping">Your customized error mapping.</param>
/// <returns>The reference to the same extended <see cref="IOcelotBuilder"/> object.</returns>
public static IOcelotBuilder AddPolly<T>(this IOcelotBuilder builder,
QosDelegatingHandlerDelegate delegatingHandler,
Dictionary<Type, Func<Exception, Error>> errorMapping)
where T : class, IPollyQoSProvider<HttpResponseMessage>
{
builder.Services
.AddSingleton(errorMapping)
.AddSingleton<IPollyQoSProvider<HttpResponseMessage>, T>()
.AddSingleton(delegatingHandler);

return builder;
}

/// <summary>
/// Adds Polly QoS provider to Ocelot with custom error mapping, but default <see cref="DelegatingHandler"/> is used.
/// </summary>
/// <typeparam name="T">QoS provider to use (by default use <see cref="PollyQoSProvider"/>).</typeparam>
/// <param name="builder">Ocelot builder to extend.</param>
/// <param name="errorMapping">Your customized error mapping.</param>
/// <returns>The reference to the same extended <see cref="IOcelotBuilder"/> object.</returns>
public static IOcelotBuilder AddPolly<T>(this IOcelotBuilder builder, Dictionary<Type, Func<Exception, Error>> errorMapping)
where T : class, IPollyQoSProvider<HttpResponseMessage> =>
AddPolly<T>(builder, DefaultDelegatingHandler, errorMapping);

/// <summary>
/// Adds Polly QoS provider to Ocelot with custom <see cref="DelegatingHandler"/> delegate, but default error mapping is used.
/// </summary>
/// <typeparam name="T">QoS provider to use (by default use <see cref="PollyQoSProvider"/>).</typeparam>
/// <param name="builder">Ocelot builder to extend.</param>
/// <param name="delegatingHandler">Your customized delegating handler (to manage QoS behavior by yourself).</param>
/// <returns>The reference to the same extended <see cref="IOcelotBuilder"/> object.</returns>
public static IOcelotBuilder AddPolly<T>(this IOcelotBuilder builder, QosDelegatingHandlerDelegate delegatingHandler)
where T : class, IPollyQoSProvider<HttpResponseMessage> =>
AddPolly<T>(builder, delegatingHandler, DefaultErrorMapping);

/// <summary>
/// Adds Polly QoS provider to Ocelot by defaults.
/// </summary>
/// <remarks>
/// Defaults:
/// <list type="bullet">
/// <item><see cref="DefaultDelegatingHandler"/></item>
/// <item><see cref="DefaultErrorMapping"/></item>
/// </list>
/// </remarks>
/// <typeparam name="T">QoS provider to use (by default use <see cref="PollyQoSProvider"/>).</typeparam>
/// <param name="builder">Ocelot builder to extend.</param>
/// <returns>The reference to the same extended <see cref="IOcelotBuilder"/> object.</returns>
public static IOcelotBuilder AddPolly<T>(this IOcelotBuilder builder)
where T : class, IPollyQoSProvider<HttpResponseMessage> =>
AddPolly<T>(builder, DefaultDelegatingHandler, DefaultErrorMapping);

/// <summary>
/// Adds Polly QoS provider to Ocelot by defaults with default QoS provider.
/// </summary>
/// <remarks>
/// Defaults:
/// <list type="bullet">
/// <item><see cref="PollyQoSProvider"/></item>
/// <item><see cref="DefaultDelegatingHandler"/></item>
/// <item><see cref="DefaultErrorMapping"/></item>
/// </list>
/// </remarks>
/// <param name="builder">Ocelot builder to extend.</param>
/// <returns>The reference to the same extended <see cref="IOcelotBuilder"/> object.</returns>
public static IOcelotBuilder AddPolly(this IOcelotBuilder builder) =>
AddPolly<PollyQoSProvider>(builder, DefaultDelegatingHandler, DefaultErrorMapping);

/// <summary>
/// Creates default delegating handler based on the <see cref="PollyPoliciesDelegatingHandler"/> type.
/// </summary>
/// <param name="route">The downstream route to apply the handler for.</param>
/// <param name="contextAccessor">The context accessor of the route.</param>
/// <param name="loggerFactory">The factory of logger.</param>
/// <returns>A <see cref="DelegatingHandler"/> object, but concreate type is the <see cref="PollyPoliciesDelegatingHandler"/> class.</returns>
public static DelegatingHandler DefaultDelegatingHandler(DownstreamRoute route, IHttpContextAccessor contextAccessor, IOcelotLoggerFactory loggerFactory)
=> new PollyPoliciesDelegatingHandler(route, contextAccessor, loggerFactory);
}

0 comments on commit 0404c24

Please sign in to comment.