Skip to content

Commit e9bdeb6

Browse files
committed
Make resilient policies configurable.
1 parent 6ac5a8c commit e9bdeb6

6 files changed

Lines changed: 129 additions & 23 deletions

File tree

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace Microsoft.eShopOnContainers.BuildingBlocks.Resilience.HttpResilience.Policies
6+
{
7+
internal class CircuitBreakerPolicy : ResilientPolicy
8+
{
9+
public CircuitBreakerPolicy(int exceptionsAllowedBeforeBreaking, int durationOfBreakInMinutes)
10+
{
11+
ExceptionsAllowedBeforeBreaking = exceptionsAllowedBeforeBreaking;
12+
DurationOfBreakInMinutes = durationOfBreakInMinutes;
13+
}
14+
15+
public int ExceptionsAllowedBeforeBreaking { get; }
16+
public int DurationOfBreakInMinutes { get; }
17+
}
18+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace Microsoft.eShopOnContainers.BuildingBlocks.Resilience.HttpResilience.Policies
6+
{
7+
internal class RetryPolicy : ResilientPolicy
8+
{
9+
public RetryPolicy(int retries, int backoffSeconds, bool exponentialBackoff)
10+
{
11+
Retries = retries;
12+
BackoffSeconds = backoffSeconds;
13+
ExponentialBackoff = exponentialBackoff;
14+
}
15+
16+
public int Retries { get; }
17+
public int BackoffSeconds { get; }
18+
public bool ExponentialBackoff { get; }
19+
}
20+
}

src/BuildingBlocks/Resilience/HttpResilience/ResilientHttpClient.cs

Lines changed: 54 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
using Microsoft.Extensions.Logging;
1+
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.HttpResilience.Policies;
2+
using Microsoft.Extensions.Logging;
23
using Newtonsoft.Json;
34
using Polly;
45
using Polly.Wrap;
56
using System;
7+
using System.Collections.Generic;
68
using System.Net;
79
using System.Net.Http;
810
using System.Threading.Tasks;
@@ -19,26 +21,58 @@ public class ResilientHttpClient : IHttpClient
1921
private PolicyWrap _policyWrapper;
2022
private ILogger<ResilientHttpClient> _logger;
2123
public HttpClient Inst => _client;
22-
public ResilientHttpClient(ILogger<ResilientHttpClient> logger)
24+
25+
public ResilientHttpClient(List<Policy> policies, ILogger<ResilientHttpClient> logger)
2326
{
2427
_client = new HttpClient();
2528
_logger = logger;
2629

2730
// Add Policies to be applied
28-
_policyWrapper = Policy.WrapAsync(
29-
CreateRetryPolicy(),
30-
CreateCircuitBreakerPolicy()
31-
);
31+
_policyWrapper = Policy.WrapAsync(policies.ToArray());
32+
}
33+
34+
public ResilientHttpClient(List<ResilientPolicy> policies, ILogger<ResilientHttpClient> logger)
35+
{
36+
_client = new HttpClient();
37+
_logger = logger;
38+
39+
// Add Policies to be applied
40+
_policyWrapper = Policy.WrapAsync(GeneratePolicies(policies));
41+
}
42+
43+
private Policy[] GeneratePolicies(IList<ResilientPolicy> policies)
44+
{
45+
var pollyPolicies = new List<Policy>();
46+
47+
foreach (var policy in policies)
48+
{
49+
switch (policy)
50+
{
51+
case RetryPolicy retryPolicy:
52+
pollyPolicies.Add(
53+
CreateRetryPolicy(
54+
retryPolicy.Retries,
55+
retryPolicy.BackoffSeconds,
56+
retryPolicy.ExponentialBackoff));
57+
break;
58+
59+
case CircuitBreakerPolicy circuitPolicy:
60+
pollyPolicies.Add(
61+
CreateCircuitBreakerPolicy(
62+
circuitPolicy.ExceptionsAllowedBeforeBreaking,
63+
circuitPolicy.DurationOfBreakInMinutes));
64+
break;
65+
}
66+
}
67+
68+
return pollyPolicies.ToArray();
3269
}
3370

34-
private Policy CreateRetryPolicy() =>
71+
private Policy CreateRetryPolicy(int retries, int backoffSeconds, bool exponentialBackoff) =>
3572
Policy.Handle<HttpRequestException>()
36-
.WaitAndRetryAsync(
37-
// number of retries
38-
6,
39-
// exponential backofff
40-
retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
41-
// on retry
73+
.WaitAndRetryAsync(
74+
retries,
75+
retryAttempt => exponentialBackoff ? TimeSpan.FromSeconds(Math.Pow(backoffSeconds, retryAttempt)) : TimeSpan.FromSeconds(backoffSeconds),
4276
(exception, timeSpan, retryCount, context) =>
4377
{
4478
var msg = $"Retry {retryCount} implemented with Polly's RetryPolicy " +
@@ -50,22 +84,20 @@ private Policy CreateRetryPolicy() =>
5084
}
5185
);
5286

53-
private Policy CreateCircuitBreakerPolicy() =>
87+
private Policy CreateCircuitBreakerPolicy(int exceptionsAllowedBeforeBreaking, int durationOfBreakInMinutes) =>
5488
Policy.Handle<HttpRequestException>()
5589
.CircuitBreakerAsync(
56-
// number of exceptions before breaking circuit
57-
5,
58-
// time circuit opened before retry
59-
TimeSpan.FromMinutes(1),
90+
exceptionsAllowedBeforeBreaking,
91+
TimeSpan.FromMinutes(durationOfBreakInMinutes),
6092
(exception, duration) =>
6193
{
62-
// on circuit opened
63-
_logger.LogTrace("Circuit breaker opened");
94+
// on circuit opened
95+
_logger.LogTrace("Circuit breaker opened");
6496
},
6597
() =>
6698
{
67-
// on circuit closed
68-
_logger.LogTrace("Circuit breaker reset");
99+
// on circuit closed
100+
_logger.LogTrace("Circuit breaker reset");
69101
}
70102
);
71103

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace Microsoft.eShopOnContainers.BuildingBlocks.Resilience.HttpResilience
6+
{
7+
public class ResilientPolicy
8+
{
9+
}
10+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.HttpResilience.Policies;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Text;
5+
6+
namespace Microsoft.eShopOnContainers.BuildingBlocks.Resilience.HttpResilience
7+
{
8+
public static class ResilientPolicyFactory
9+
{
10+
public static ResilientPolicy CreateRetryPolicy(int retries, int backoffSeconds, bool exponentialBackoff)
11+
{
12+
return new RetryPolicy(retries, backoffSeconds, exponentialBackoff);
13+
}
14+
15+
public static ResilientPolicy CreateCiscuitBreakerPolicy(int exceptionsAllowedBeforeBreaking, int durationOfBreakInMinutes)
16+
{
17+
return new CircuitBreakerPolicy(exceptionsAllowedBeforeBreaking, durationOfBreakInMinutes);
18+
}
19+
}
20+
}

src/Web/WebMVC/Startup.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,14 @@ public void ConfigureServices(IServiceCollection services)
5858
services.AddTransient<IBasketService, BasketService>();
5959
services.AddTransient<IIdentityParser<ApplicationUser>, IdentityParser>();
6060

61-
if(Configuration.GetValue<string>("ActivateCircuitBreaker") == bool.TrueString)
61+
if (Configuration.GetValue<string>("ActivateCircuitBreaker") == bool.TrueString)
6262
{
63+
services.AddSingleton(
64+
new List<ResilientPolicy>
65+
{
66+
ResilientPolicyFactory.CreateRetryPolicy(6, 2, true),
67+
ResilientPolicyFactory.CreateCiscuitBreakerPolicy(5, 1)
68+
});
6369
services.AddTransient<IHttpClient, ResilientHttpClient>();
6470
}
6571
else

0 commit comments

Comments
 (0)