retry policy defined via config

This commit is contained in:
Igor Sychev 2017-10-12 09:25:01 +01:00
parent 8d033f0951
commit 1b38589ff0
19 changed files with 191 additions and 54 deletions

View File

@ -15,16 +15,17 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
{ {
private readonly IConnectionFactory _connectionFactory; private readonly IConnectionFactory _connectionFactory;
private readonly ILogger<DefaultRabbitMQPersistentConnection> _logger; private readonly ILogger<DefaultRabbitMQPersistentConnection> _logger;
private readonly int _retryCount;
IConnection _connection; IConnection _connection;
bool _disposed; bool _disposed;
object sync_root = new object(); object sync_root = new object();
public DefaultRabbitMQPersistentConnection(IConnectionFactory connectionFactory,ILogger<DefaultRabbitMQPersistentConnection> logger) public DefaultRabbitMQPersistentConnection(IConnectionFactory connectionFactory, ILogger<DefaultRabbitMQPersistentConnection> logger, int retryCount = 5)
{ {
_connectionFactory = connectionFactory ?? throw new ArgumentNullException(nameof(connectionFactory)); _connectionFactory = connectionFactory ?? throw new ArgumentNullException(nameof(connectionFactory));
_logger = logger ?? throw new ArgumentNullException(nameof(logger)); _logger = logger ?? throw new ArgumentNullException(nameof(logger));
_retryCount = retryCount;
} }
public bool IsConnected public bool IsConnected
@ -69,7 +70,7 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
{ {
var policy = RetryPolicy.Handle<SocketException>() var policy = RetryPolicy.Handle<SocketException>()
.Or<BrokerUnreachableException>() .Or<BrokerUnreachableException>()
.WaitAndRetry(5, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (ex, time) => .WaitAndRetry(_retryCount, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (ex, time) =>
{ {
_logger.LogWarning(ex.ToString()); _logger.LogWarning(ex.ToString());
} }
@ -88,7 +89,7 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
_connection.ConnectionBlocked += OnConnectionBlocked; _connection.ConnectionBlocked += OnConnectionBlocked;
_logger.LogInformation($"RabbitMQ persistent connection acquired a connection {_connection.Endpoint.HostName} and is subscribed to failure events"); _logger.LogInformation($"RabbitMQ persistent connection acquired a connection {_connection.Endpoint.HostName} and is subscribed to failure events");
return true; return true;
} }
else else

View File

@ -26,19 +26,20 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
private readonly IEventBusSubscriptionsManager _subsManager; private readonly IEventBusSubscriptionsManager _subsManager;
private readonly ILifetimeScope _autofac; private readonly ILifetimeScope _autofac;
private readonly string AUTOFAC_SCOPE_NAME = "eshop_event_bus"; private readonly string AUTOFAC_SCOPE_NAME = "eshop_event_bus";
private readonly int _retryCount;
private IModel _consumerChannel; private IModel _consumerChannel;
private string _queueName; private string _queueName;
public EventBusRabbitMQ(IRabbitMQPersistentConnection persistentConnection, ILogger<EventBusRabbitMQ> logger, public EventBusRabbitMQ(IRabbitMQPersistentConnection persistentConnection, ILogger<EventBusRabbitMQ> logger,
ILifetimeScope autofac, IEventBusSubscriptionsManager subsManager) ILifetimeScope autofac, IEventBusSubscriptionsManager subsManager, int retryCount = 5)
{ {
_persistentConnection = persistentConnection ?? throw new ArgumentNullException(nameof(persistentConnection)); _persistentConnection = persistentConnection ?? throw new ArgumentNullException(nameof(persistentConnection));
_logger = logger ?? throw new ArgumentNullException(nameof(logger)); _logger = logger ?? throw new ArgumentNullException(nameof(logger));
_subsManager = subsManager ?? new InMemoryEventBusSubscriptionsManager(); _subsManager = subsManager ?? new InMemoryEventBusSubscriptionsManager();
_consumerChannel = CreateConsumerChannel(); _consumerChannel = CreateConsumerChannel();
_autofac = autofac; _autofac = autofac;
_retryCount = retryCount;
_subsManager.OnEventRemoved += SubsManager_OnEventRemoved; _subsManager.OnEventRemoved += SubsManager_OnEventRemoved;
} }
@ -72,7 +73,7 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
var policy = RetryPolicy.Handle<BrokerUnreachableException>() var policy = RetryPolicy.Handle<BrokerUnreachableException>()
.Or<SocketException>() .Or<SocketException>()
.WaitAndRetry(5, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (ex, time) => .WaitAndRetry(_retryCount, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (ex, time) =>
{ {
_logger.LogWarning(ex.ToString()); _logger.LogWarning(ex.ToString());
}); });

View File

@ -120,7 +120,13 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
factory.Password = Configuration["EventBusPassword"]; factory.Password = Configuration["EventBusPassword"];
} }
return new DefaultRabbitMQPersistentConnection(factory, logger); var retryCount = 5;
if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"]))
{
retryCount = int.Parse(Configuration["EventBusRetryCount"]);
}
return new DefaultRabbitMQPersistentConnection(factory, logger, retryCount);
}); });
} }
@ -247,7 +253,21 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
} }
else else
{ {
services.AddSingleton<IEventBus, EventBusRabbitMQ>(); services.AddSingleton<IEventBus, EventBusRabbitMQ>(sp =>
{
var rabbitMQPersistentConnection = sp.GetRequiredService<IRabbitMQPersistentConnection>();
var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>();
var logger = sp.GetRequiredService<ILogger<EventBusRabbitMQ>>();
var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>();
var retryCount = 5;
if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"]))
{
retryCount = int.Parse(Configuration["EventBusRetryCount"]);
}
return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, retryCount);
});
} }
services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>(); services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>();

View File

@ -13,5 +13,6 @@
"SubscriptionClientName": "Basket", "SubscriptionClientName": "Basket",
"ApplicationInsights": { "ApplicationInsights": {
"InstrumentationKey": "" "InstrumentationKey": ""
} },
"EventBusRetryCount": 5
} }

View File

@ -35,7 +35,7 @@
Configuration = configuration; Configuration = configuration;
} }
public IConfiguration Configuration { get; } public IConfiguration Configuration { get; }
public IServiceProvider ConfigureServices(IServiceCollection services) public IServiceProvider ConfigureServices(IServiceCollection services)
{ {
@ -161,7 +161,13 @@
factory.Password = Configuration["EventBusPassword"]; factory.Password = Configuration["EventBusPassword"];
} }
return new DefaultRabbitMQPersistentConnection(factory, logger); var retryCount = 5;
if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"]))
{
retryCount = int.Parse(Configuration["EventBusRetryCount"]);
}
return new DefaultRabbitMQPersistentConnection(factory, logger, retryCount);
}); });
} }
@ -188,7 +194,7 @@
loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'"); loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'");
app.UsePathBase(pathBase); app.UsePathBase(pathBase);
} }
app.UseCors("CorsPolicy"); app.UseCors("CorsPolicy");
app.UseMvcWithDefaultRoute(); app.UseMvcWithDefaultRoute();
@ -221,7 +227,21 @@
} }
else else
{ {
services.AddSingleton<IEventBus, EventBusRabbitMQ>(); services.AddSingleton<IEventBus, EventBusRabbitMQ>(sp =>
{
var rabbitMQPersistentConnection = sp.GetRequiredService<IRabbitMQPersistentConnection>();
var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>();
var logger = sp.GetRequiredService<ILogger<EventBusRabbitMQ>>();
var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>();
var retryCount = 5;
if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"]))
{
retryCount = int.Parse(Configuration["EventBusRetryCount"]);
}
return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, retryCount);
});
} }
services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>(); services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>();

View File

@ -15,5 +15,6 @@
"SubscriptionClientName": "Catalog", "SubscriptionClientName": "Catalog",
"ApplicationInsights": { "ApplicationInsights": {
"InstrumentationKey": "" "InstrumentationKey": ""
} },
"EventBusRetryCount": 5
} }

View File

@ -87,7 +87,13 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API
factory.Password = Configuration["EventBusPassword"]; factory.Password = Configuration["EventBusPassword"];
} }
return new DefaultRabbitMQPersistentConnection(factory, logger); var retryCount = 5;
if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"]))
{
retryCount = int.Parse(Configuration["EventBusRetryCount"]);
}
return new DefaultRabbitMQPersistentConnection(factory, logger, retryCount);
}); });
} }
@ -217,7 +223,21 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API
} }
else else
{ {
services.AddSingleton<IEventBus, EventBusRabbitMQ>(); services.AddSingleton<IEventBus, EventBusRabbitMQ>(sp =>
{
var rabbitMQPersistentConnection = sp.GetRequiredService<IRabbitMQPersistentConnection>();
var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>();
var logger = sp.GetRequiredService<ILogger<EventBusRabbitMQ>>();
var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>();
var retryCount = 5;
if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"]))
{
retryCount = int.Parse(Configuration["EventBusRetryCount"]);
}
return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, retryCount);
});
} }
services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>(); services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>();

View File

@ -1,10 +0,0 @@
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}

View File

@ -14,5 +14,6 @@
"SubscriptionClientName": "Locations", "SubscriptionClientName": "Locations",
"ApplicationInsights": { "ApplicationInsights": {
"InstrumentationKey": "" "InstrumentationKey": ""
} },
"EventBusRetryCount": 5
} }

View File

@ -122,7 +122,14 @@
{ {
factory.Password = Configuration["EventBusPassword"]; factory.Password = Configuration["EventBusPassword"];
} }
return new DefaultRabbitMQPersistentConnection(factory, logger);
var retryCount = 5;
if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"]))
{
retryCount = int.Parse(Configuration["EventBusRetryCount"]);
}
return new DefaultRabbitMQPersistentConnection(factory, logger, retryCount);
}); });
} }
@ -242,7 +249,21 @@
} }
else else
{ {
services.AddSingleton<IEventBus, EventBusRabbitMQ>(); services.AddSingleton<IEventBus, EventBusRabbitMQ>(sp =>
{
var rabbitMQPersistentConnection = sp.GetRequiredService<IRabbitMQPersistentConnection>();
var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>();
var logger = sp.GetRequiredService<ILogger<EventBusRabbitMQ>>();
var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>();
var retryCount = 5;
if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"]))
{
retryCount = int.Parse(Configuration["EventBusRetryCount"]);
}
return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, retryCount);
});
} }
services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>(); services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>();

View File

@ -1,8 +0,0 @@
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Warning"
}
}
}

View File

@ -15,5 +15,6 @@
"AzureStorageEnabled": false, "AzureStorageEnabled": false,
"ApplicationInsights": { "ApplicationInsights": {
"InstrumentationKey": "" "InstrumentationKey": ""
} },
"EventBusRetryCount": 5
} }

View File

@ -180,7 +180,13 @@
factory.Password = Configuration["EventBusPassword"]; factory.Password = Configuration["EventBusPassword"];
} }
return new DefaultRabbitMQPersistentConnection(factory, logger); var retryCount = 5;
if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"]))
{
retryCount = int.Parse(Configuration["EventBusRetryCount"]);
}
return new DefaultRabbitMQPersistentConnection(factory, logger, retryCount);
}); });
} }
@ -284,7 +290,21 @@
} }
else else
{ {
services.AddSingleton<IEventBus, EventBusRabbitMQ>(); services.AddSingleton<IEventBus, EventBusRabbitMQ>(sp =>
{
var rabbitMQPersistentConnection = sp.GetRequiredService<IRabbitMQPersistentConnection>();
var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>();
var logger = sp.GetRequiredService<ILogger<EventBusRabbitMQ>>();
var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>();
var retryCount = 5;
if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"]))
{
retryCount = int.Parse(Configuration["EventBusRetryCount"]);
}
return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, retryCount);
});
} }
services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>(); services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>();

View File

@ -16,5 +16,6 @@
"CheckUpdateTime": "30000", "CheckUpdateTime": "30000",
"ApplicationInsights": { "ApplicationInsights": {
"InstrumentationKey": "" "InstrumentationKey": ""
} },
"EventBusRetryCount": 5
} }

View File

@ -74,7 +74,13 @@ namespace Payment.API
factory.Password = Configuration["EventBusPassword"]; factory.Password = Configuration["EventBusPassword"];
} }
return new DefaultRabbitMQPersistentConnection(factory, logger); var retryCount = 5;
if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"]))
{
retryCount = int.Parse(Configuration["EventBusRetryCount"]);
}
return new DefaultRabbitMQPersistentConnection(factory, logger, retryCount);
}); });
} }
@ -123,7 +129,21 @@ namespace Payment.API
} }
else else
{ {
services.AddSingleton<IEventBus, EventBusRabbitMQ>(); services.AddSingleton<IEventBus, EventBusRabbitMQ>(sp =>
{
var rabbitMQPersistentConnection = sp.GetRequiredService<IRabbitMQPersistentConnection>();
var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>();
var logger = sp.GetRequiredService<ILogger<EventBusRabbitMQ>>();
var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>();
var retryCount = 5;
if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"]))
{
retryCount = int.Parse(Configuration["EventBusRetryCount"]);
}
return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, retryCount);
});
} }
services.AddTransient<OrderStatusChangedToStockConfirmedIntegrationEventHandler>(); services.AddTransient<OrderStatusChangedToStockConfirmedIntegrationEventHandler>();

View File

@ -10,5 +10,6 @@
"SubscriptionClientName": "Payment", "SubscriptionClientName": "Payment",
"ApplicationInsights": { "ApplicationInsights": {
"InstrumentationKey": "" "InstrumentationKey": ""
} },
"EventBusRetryCount": 5
} }

View File

@ -9,11 +9,18 @@ namespace Microsoft.eShopOnContainers.WebMVC.Infrastructure
public class ResilientHttpClientFactory : IResilientHttpClientFactory public class ResilientHttpClientFactory : IResilientHttpClientFactory
{ {
private readonly ILogger<ResilientHttpClient> _logger; private readonly ILogger<ResilientHttpClient> _logger;
private readonly int _retryCount;
private readonly int _exceptionsAllowedBeforeBreaking;
public ResilientHttpClientFactory(ILogger<ResilientHttpClient> logger) public ResilientHttpClientFactory(ILogger<ResilientHttpClient> logger, int exceptionsAllowedBeforeBreaking = 5, int retryCount = 6)
=>_logger = logger; {
_logger = logger;
_exceptionsAllowedBeforeBreaking = exceptionsAllowedBeforeBreaking;
_retryCount = retryCount;
}
public ResilientHttpClient CreateResilientHttpClient()
public ResilientHttpClient CreateResilientHttpClient()
=> new ResilientHttpClient((origin) => CreatePolicies(), _logger); => new ResilientHttpClient((origin) => CreatePolicies(), _logger);
private Policy[] CreatePolicies() private Policy[] CreatePolicies()
@ -22,7 +29,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Infrastructure
Policy.Handle<HttpRequestException>() Policy.Handle<HttpRequestException>()
.WaitAndRetryAsync( .WaitAndRetryAsync(
// number of retries // number of retries
6, _retryCount,
// exponential backofff // exponential backofff
retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
// on retry // on retry
@ -36,9 +43,9 @@ namespace Microsoft.eShopOnContainers.WebMVC.Infrastructure
_logger.LogDebug(msg); _logger.LogDebug(msg);
}), }),
Policy.Handle<HttpRequestException>() Policy.Handle<HttpRequestException>()
.CircuitBreakerAsync( .CircuitBreakerAsync(
// number of exceptions before breaking circuit // number of exceptions before breaking circuit
5, _exceptionsAllowedBeforeBreaking,
// time circuit opened before retry // time circuit opened before retry
TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1),
(exception, duration) => (exception, duration) =>
@ -51,6 +58,6 @@ namespace Microsoft.eShopOnContainers.WebMVC.Infrastructure
// on circuit closed // on circuit closed
_logger.LogTrace("Circuit breaker reset"); _logger.LogTrace("Circuit breaker reset");
}) })
}; };
} }
} }

View File

@ -79,7 +79,24 @@ namespace Microsoft.eShopOnContainers.WebMVC
if (Configuration.GetValue<string>("UseResilientHttp") == bool.TrueString) if (Configuration.GetValue<string>("UseResilientHttp") == bool.TrueString)
{ {
services.AddSingleton<IResilientHttpClientFactory, ResilientHttpClientFactory>(); services.AddSingleton<IResilientHttpClientFactory, ResilientHttpClientFactory>(sp =>
{
var logger = sp.GetRequiredService<ILogger<ResilientHttpClient>>();
var retryCount = 6;
if (!string.IsNullOrEmpty(Configuration["HttpClientRetryCount"]))
{
retryCount = int.Parse(Configuration["HttpClientRetryCount"]);
}
var exceptionsAllowedBeforeBreaking = 5;
if (!string.IsNullOrEmpty(Configuration["HttpClientExceptionsAllowedBeforeBreaking"]))
{
exceptionsAllowedBeforeBreaking = int.Parse(Configuration["HttpClientExceptionsAllowedBeforeBreaking"]);
}
return new ResilientHttpClientFactory(logger, exceptionsAllowedBeforeBreaking, retryCount);
});
services.AddSingleton<IHttpClient, ResilientHttpClient>(sp => sp.GetService<IResilientHttpClientFactory>().CreateResilientHttpClient()); services.AddSingleton<IHttpClient, ResilientHttpClient>(sp => sp.GetService<IResilientHttpClientFactory>().CreateResilientHttpClient());
} }
else else

View File

@ -21,5 +21,7 @@
}, },
"ApplicationInsights": { "ApplicationInsights": {
"InstrumentationKey": "" "InstrumentationKey": ""
} },
"HttpClientRetryCount": 6,
"HttpClientExceptionsAllowedBeforeBreaking": 5
} }