Skip to content

Commit b42fe35

Browse files
committed
Resilience enhancements.
MVC app now waits other containers
1 parent af2d37b commit b42fe35

10 files changed

Lines changed: 75 additions & 35 deletions

File tree

eShopOnContainers-ServicesAndWebApps.sln

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
Microsoft Visual Studio Solution File, Format Version 12.00
33
# Visual Studio 15
4-
VisualStudioVersion = 15.0.26403.3
4+
VisualStudioVersion = 15.0.26430.12
55
MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{932D8224-11F6-4D07-B109-DA28AD288A63}"
77
EndProject

src/BuildingBlocks/Resilience/Resilience.Http/ResilientHttpClient.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ private Task<HttpResponseMessage> DoPostPutAsync<T>(HttpMethod method, string ur
9696
// as it is disposed after each call
9797
var origin = GetOriginFromUri(uri);
9898

99-
return HttpInvoker(origin, () =>
99+
return HttpInvoker(origin, async () =>
100100
{
101101
var requestMessage = new HttpRequestMessage(method, uri);
102102

@@ -112,7 +112,7 @@ private Task<HttpResponseMessage> DoPostPutAsync<T>(HttpMethod method, string ur
112112
requestMessage.Headers.Add("x-requestid", requestId);
113113
}
114114

115-
var response = _client.SendAsync(requestMessage).Result;
115+
var response = await _client.SendAsync(requestMessage);
116116

117117
// raise exception if HttpResponseCode 500
118118
// needed for circuit breaker to track fails
@@ -122,7 +122,7 @@ private Task<HttpResponseMessage> DoPostPutAsync<T>(HttpMethod method, string ur
122122
throw new HttpRequestException();
123123
}
124124

125-
return Task.FromResult(response);
125+
return response;
126126
});
127127
}
128128

@@ -132,13 +132,13 @@ private async Task<T> HttpInvoker<T>(string origin, Func<Task<T>> action)
132132

133133
if (!_policyWrappers.TryGetValue(normalizedOrigin, out PolicyWrap policyWrap))
134134
{
135-
policyWrap = Policy.Wrap(_policyCreator(normalizedOrigin).ToArray());
135+
policyWrap = Policy.WrapAsync(_policyCreator(normalizedOrigin).ToArray());
136136
_policyWrappers.TryAdd(normalizedOrigin, policyWrap);
137137
}
138138

139139
// Executes the action applying all
140140
// the policies defined in the wrapper
141-
return await policyWrap.Execute(action, new Context(normalizedOrigin));
141+
return await policyWrap.ExecuteAsync(action, new Context(normalizedOrigin));
142142
}
143143

144144

src/Services/Catalog/Catalog.API/Catalog.API.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="1.1.2" />
4646
<PackageReference Include="Newtonsoft.Json" Version="10.0.2" />
4747
<PackageReference Include="Swashbuckle.AspNetCore" Version="1.0.0" />
48+
<PackageReference Include="Polly" Version="5.1.0" />
4849
</ItemGroup>
4950

5051
<ItemGroup>

src/Services/Catalog/Catalog.API/Startup.cs

Lines changed: 24 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@
1717
using Microsoft.Extensions.HealthChecks;
1818
using Microsoft.Extensions.Logging;
1919
using Microsoft.Extensions.Options;
20+
using Polly;
2021
using RabbitMQ.Client;
2122
using System;
2223
using System.Data.Common;
2324
using System.Data.SqlClient;
2425
using System.Reflection;
26+
using System.Threading.Tasks;
2527

2628
public class Startup
2729
{
@@ -85,7 +87,7 @@ public void ConfigureServices(IServiceCollection services)
8587
services.AddSwaggerGen(options =>
8688
{
8789
options.DescribeAllEnumsAsStrings();
88-
options.SwaggerDoc("v1",new Swashbuckle.AspNetCore.Swagger.Info
90+
options.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info
8991
{
9092
Title = "eShopOnContainers - Catalog HTTP API",
9193
Version = "v1",
@@ -144,11 +146,7 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerF
144146
var context = (CatalogContext)app
145147
.ApplicationServices.GetService(typeof(CatalogContext));
146148

147-
WaitForSqlAvailability(context, loggerFactory);
148-
149-
//Seed Data
150-
CatalogContextSeed.SeedAsync(app, loggerFactory)
151-
.Wait();
149+
WaitForSqlAvailabilityAsync(context, loggerFactory, app).Wait();
152150

153151
var integrationEventLogContext = new IntegrationEventLogContext(
154152
new DbContextOptionsBuilder<IntegrationEventLogContext>()
@@ -158,28 +156,28 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerF
158156
integrationEventLogContext.Database.Migrate();
159157
}
160158

161-
private void WaitForSqlAvailability(CatalogContext ctx, ILoggerFactory loggerFactory, int? retry = 0)
159+
private async Task WaitForSqlAvailabilityAsync(CatalogContext ctx, ILoggerFactory loggerFactory, IApplicationBuilder app, int retries = 0)
162160
{
163-
int retryForAvailability = retry.Value;
164-
165-
try
166-
{
167-
ctx.Database.OpenConnection();
168-
}
169-
catch (SqlException ex)
170-
{
171-
if (retryForAvailability < 10)
172-
{
173-
retryForAvailability++;
174-
var log = loggerFactory.CreateLogger(nameof(Startup));
175-
log.LogError(ex.Message);
176-
WaitForSqlAvailability(ctx, loggerFactory, retryForAvailability);
177-
}
178-
}
179-
finally
161+
var logger = loggerFactory.CreateLogger(nameof(Startup));
162+
var policy = CreatePolicy(retries, logger, nameof (WaitForSqlAvailabilityAsync));
163+
await policy.ExecuteAsync(async () =>
180164
{
181-
ctx.Database.CloseConnection();
182-
}
165+
await CatalogContextSeed.SeedAsync(app, loggerFactory);
166+
});
167+
168+
}
169+
170+
private Policy CreatePolicy(int retries, ILogger logger, string prefix)
171+
{
172+
return Policy.Handle<SqlException>().
173+
WaitAndRetryAsync(
174+
retryCount: retries,
175+
sleepDurationProvider: retry => TimeSpan.FromSeconds(5),
176+
onRetry: (exception, timeSpan, retry, ctx) =>
177+
{
178+
logger.LogTrace($"[{prefix}] Exception {exception.GetType().Name} with message ${exception.Message} detected on attempt {retry} of {retries}");
179+
}
180+
);
183181
}
184182
}
185183
}

src/Services/Ordering/Ordering.API/Ordering.API.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
<PackageReference Include="IdentityServer4.AccessTokenValidation" Version="1.2.0" />
5959
<PackageReference Include="Dapper" Version="1.50.2" />
6060
<PackageReference Include="System.ValueTuple" Version="4.3.1" />
61+
<PackageReference Include="Polly" Version="5.1.0" />
6162
</ItemGroup>
6263

6364
<ItemGroup>

src/Services/Ordering/Ordering.API/Startup.cs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,13 @@
2323
using Microsoft.Extensions.HealthChecks;
2424
using Microsoft.Extensions.Logging;
2525
using Ordering.Infrastructure;
26+
using Polly;
2627
using RabbitMQ.Client;
2728
using System;
2829
using System.Data.Common;
30+
using System.Data.SqlClient;
2931
using System.Reflection;
32+
using System.Threading.Tasks;
3033

3134
public class Startup
3235
{
@@ -156,7 +159,7 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerF
156159
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
157160
});
158161

159-
OrderingContextSeed.SeedAsync(app).Wait();
162+
WaitForSqlAvailabilityAsync(loggerFactory, app).Wait();
160163

161164
var integrationEventLogContext = new IntegrationEventLogContext(
162165
new DbContextOptionsBuilder<IntegrationEventLogContext>()
@@ -175,5 +178,30 @@ protected virtual void ConfigureAuth(IApplicationBuilder app)
175178
RequireHttpsMetadata = false
176179
});
177180
}
181+
182+
183+
private async Task WaitForSqlAvailabilityAsync(ILoggerFactory loggerFactory, IApplicationBuilder app, int retries = 0)
184+
{
185+
var logger = loggerFactory.CreateLogger(nameof(Startup));
186+
var policy = CreatePolicy(retries, logger, nameof(WaitForSqlAvailabilityAsync));
187+
await policy.ExecuteAsync(async () =>
188+
{
189+
await OrderingContextSeed.SeedAsync(app);
190+
});
191+
192+
}
193+
194+
private Policy CreatePolicy(int retries, ILogger logger, string prefix)
195+
{
196+
return Policy.Handle<SqlException>().
197+
WaitAndRetryAsync(
198+
retryCount: retries,
199+
sleepDurationProvider: retry => TimeSpan.FromSeconds(5),
200+
onRetry: (exception, timeSpan, retry, ctx) =>
201+
{
202+
logger.LogTrace($"[{prefix}] Exception {exception.GetType().Name} with message ${exception.Message} detected on attempt {retry} of {retries}");
203+
}
204+
);
205+
}
178206
}
179207
}

src/Web/WebMVC/Infrastructure/ResilientHttpClientFactory.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ private Policy[] CreatePolicies()
2020
=> new Policy[]
2121
{
2222
Policy.Handle<HttpRequestException>()
23-
.WaitAndRetry(
23+
.WaitAndRetryAsync(
2424
// number of retries
2525
6,
2626
// exponential backofff
@@ -36,7 +36,7 @@ private Policy[] CreatePolicies()
3636
_logger.LogDebug(msg);
3737
}),
3838
Policy.Handle<HttpRequestException>()
39-
.CircuitBreaker(
39+
.CircuitBreakerAsync(
4040
// number of exceptions before breaking circuit
4141
5,
4242
// time circuit opened before retry

test/Services/FunctionalTests/FunctionalTests.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,8 @@
3838
</None>
3939
</ItemGroup>
4040

41+
<ItemGroup>
42+
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
43+
</ItemGroup>
44+
4145
</Project>

test/Services/IntegrationTests/IntegrationTests.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,8 @@
4646
</Content>
4747
</ItemGroup>
4848

49+
<ItemGroup>
50+
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
51+
</ItemGroup>
52+
4953
</Project>

test/Services/UnitTest/UnitTest.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,8 @@
2828
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="1.1.2" />
2929
</ItemGroup>
3030

31+
<ItemGroup>
32+
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
33+
</ItemGroup>
34+
3135
</Project>

0 commit comments

Comments
 (0)