-
Notifications
You must be signed in to change notification settings - Fork 129
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Migrate the first half of the async demos (#46)
* Move statistics fields from SyncDemo to DemoBase * Migrate async demo 0 * Migrate async demo 1 * Migrate async demo 2 * Migrate async demo 3 * Migrate async demo 4 * Migrate async demo 5 * Polish comments
- Loading branch information
1 parent
137bab1
commit fe72f44
Showing
12 changed files
with
362 additions
and
428 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,12 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using PollyDemos.OutputHelpers; | ||
using PollyDemos.OutputHelpers; | ||
|
||
namespace PollyDemos.Async | ||
{ | ||
public abstract class AsyncDemo : DemoBase | ||
{ | ||
public abstract Task ExecuteAsync(CancellationToken cancellationToken, IProgress<DemoProgress> progress); | ||
|
||
public async Task<string> IssueRequestAndProcessResponseAsync(HttpClient client, CancellationToken cancellationToken) | ||
=> await client.GetStringAsync($"{Configuration.WEB_API_ROOT}/api/values/{totalRequests}", cancellationToken); | ||
} | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
using PollyDemos.OutputHelpers; | ||
|
||
namespace PollyDemos.Async | ||
{ | ||
/// <summary> | ||
/// Uses no strategy. Demonstrates behavior of 'faulting server' we are testing against. | ||
/// Loops through a series of HTTP requests, keeping track of each requested | ||
/// item and reporting server failures when encountering exceptions. | ||
/// </summary> | ||
public class AsyncDemo00_NoStrategy : AsyncDemo | ||
{ | ||
public override string Description => | ||
"This demo demonstrates how our faulting server behaves, with no Polly strategy in use."; | ||
|
||
public override async Task ExecuteAsync(CancellationToken cancellationToken, IProgress<DemoProgress> progress) | ||
{ | ||
ArgumentNullException.ThrowIfNull(progress); | ||
|
||
// Let's call a web API service to make repeated requests to a server. | ||
// The service is configured to fail after 3 requests in 5 seconds. | ||
|
||
eventualSuccesses = 0; | ||
eventualFailures = 0; | ||
totalRequests = 0; | ||
|
||
PrintHeader(progress, nameof(AsyncDemo00_NoStrategy)); | ||
|
||
var client = new HttpClient(); | ||
var internalCancel = false; | ||
|
||
// Do the following until a key is pressed | ||
while (!(internalCancel || cancellationToken.IsCancellationRequested)) | ||
{ | ||
totalRequests++; | ||
|
||
try | ||
{ | ||
// Make a request and get a response | ||
var responseBody = await IssueRequestAndProcessResponseAsync(client, cancellationToken); | ||
|
||
// Display the response message on the console | ||
progress.Report(ProgressWithMessage($"Response : {responseBody}", Color.Green)); | ||
eventualSuccesses++; | ||
} | ||
catch (Exception e) | ||
{ | ||
progress.Report(ProgressWithMessage($"Request {totalRequests} eventually failed with: {e.Message}", Color.Red)); | ||
eventualFailures++; | ||
} | ||
|
||
await Task.Delay(TimeSpan.FromSeconds(0.5), cancellationToken); | ||
internalCancel = TerminateDemosByKeyPress && Console.KeyAvailable; | ||
} | ||
} | ||
|
||
public override Statistic[] LatestStatistics => new Statistic[] | ||
{ | ||
new("Total requests made", totalRequests), | ||
new("Requests which eventually succeeded", eventualSuccesses, Color.Green), | ||
new("Retries made to help achieve success", retries, Color.Yellow), | ||
new("Requests which eventually failed", eventualFailures, Color.Red), | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,97 +1,91 @@ | ||
using Polly; | ||
using System; | ||
using System.Net.Http; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using PollyDemos.OutputHelpers; | ||
using PollyDemos.OutputHelpers; | ||
|
||
namespace PollyDemos.Async | ||
{ | ||
/// <summary> | ||
/// Demonstrates the Retry policy coming into action. | ||
/// Loops through a series of Http requests, keeping track of each requested | ||
/// Demonstrates the Retry strategy coming into action. | ||
/// Loops through a series of HTTP requests, keeping track of each requested | ||
/// item and reporting server failures when encountering exceptions. | ||
/// | ||
/// Observations: There's no wait among these retries. Can be appropriate sometimes. | ||
/// | ||
/// Observations: There's no wait among these retries. It can be appropriate sometimes. | ||
/// In this case, no wait hasn't given underlying system time to recover, so calls still fail despite retries. | ||
/// </summary> | ||
public class AsyncDemo01_RetryNTimes : AsyncDemo | ||
{ | ||
private int totalRequests; | ||
private int eventualSuccesses; | ||
private int retries; | ||
private int eventualFailures; | ||
|
||
public override string Description => | ||
"This demo demonstrates a first Retry. It retries three times, immediately."; | ||
|
||
public override async Task ExecuteAsync(CancellationToken cancellationToken, IProgress<DemoProgress> progress) | ||
{ | ||
if (progress == null) throw new ArgumentNullException(nameof(progress)); | ||
ArgumentNullException.ThrowIfNull(progress); | ||
|
||
// Let's call a web API service to make repeated requests to a server. | ||
// The service is configured to fail after 3 requests in 5 seconds. | ||
|
||
eventualSuccesses = 0; | ||
retries = 0; | ||
eventualFailures = 0; | ||
totalRequests = 0; | ||
|
||
progress.Report(ProgressWithMessage(nameof(AsyncDemo01_RetryNTimes))); | ||
progress.Report(ProgressWithMessage("======")); | ||
progress.Report(ProgressWithMessage(string.Empty)); | ||
|
||
// Define our policy: | ||
var policy = Policy.Handle<Exception>().RetryAsync(3, (exception, attempt) => | ||
{ | ||
// This is your new exception handler! | ||
// Tell the user what they've won! | ||
progress.Report(ProgressWithMessage("Policy logging: " + exception.Message, Color.Yellow)); | ||
retries++; | ||
}); | ||
PrintHeader(progress, nameof(AsyncDemo01_RetryNTimes)); | ||
|
||
using (var client = new HttpClient()) | ||
// Define our strategy: | ||
var strategy = new ResiliencePipelineBuilder().AddRetry(new() | ||
{ | ||
totalRequests = 0; | ||
var internalCancel = false; | ||
// Do the following until a key is pressed | ||
while (!internalCancel && !cancellationToken.IsCancellationRequested) | ||
ShouldHandle = new PredicateBuilder().Handle<Exception>(), | ||
MaxRetryAttempts = 3, // Retry up to 3 times | ||
OnRetry = args => | ||
{ | ||
totalRequests++; | ||
// Due to how we have defined ShouldHandle, this delegate is called only if an exception occurred. | ||
// Note the ! sign (null-forgiving operator) at the end of the command. | ||
var exception = args.Outcome.Exception!; // The Exception property is nullable | ||
try | ||
{ | ||
// Retry the following call according to the policy - 3 times. | ||
await policy.ExecuteAsync(async () => | ||
{ | ||
// This code is executed within the Policy | ||
// Tell the user what happened | ||
progress.Report(ProgressWithMessage($"Strategy logging: {exception.Message}", Color.Yellow)); | ||
retries++; | ||
return default; | ||
} | ||
}).Build(); | ||
|
||
// Make a request and get a response | ||
var msg = await client.GetStringAsync( | ||
Configuration.WEB_API_ROOT + "/api/values/" + totalRequests); | ||
var client = new HttpClient(); | ||
var internalCancel = false; | ||
|
||
// Display the response message on the console | ||
progress.Report(ProgressWithMessage("Response : " + msg, Color.Green)); | ||
eventualSuccesses++; | ||
}); | ||
} | ||
catch (Exception e) | ||
// Do the following until a key is pressed | ||
while (!(internalCancel || cancellationToken.IsCancellationRequested)) | ||
{ | ||
totalRequests++; | ||
|
||
try | ||
{ | ||
// Retry the following call according to the strategy. | ||
// The cancellationToken passed in to ExecuteAsync() enables the strategy to cancel retries when the token is signalled. | ||
await strategy.ExecuteAsync(async token => | ||
{ | ||
progress.Report(ProgressWithMessage( | ||
"Request " + totalRequests + " eventually failed with: " + e.Message, Color.Red)); | ||
eventualFailures++; | ||
} | ||
// This code is executed within the strategy | ||
// Wait half second | ||
await Task.Delay(TimeSpan.FromSeconds(0.5), cancellationToken); | ||
var responseBody = await IssueRequestAndProcessResponseAsync(client, token); | ||
progress.Report(ProgressWithMessage($"Response : {responseBody}", Color.Green)); | ||
eventualSuccesses++; | ||
internalCancel = TerminateDemosByKeyPress && Console.KeyAvailable; | ||
}, cancellationToken); | ||
} | ||
catch (Exception e) | ||
{ | ||
progress.Report(ProgressWithMessage($"Request {totalRequests} eventually failed with: {e.Message}", Color.Red)); | ||
eventualFailures++; | ||
} | ||
|
||
await Task.Delay(TimeSpan.FromSeconds(0.5), cancellationToken); | ||
internalCancel = TerminateDemosByKeyPress && Console.KeyAvailable; | ||
} | ||
} | ||
|
||
public override Statistic[] LatestStatistics => new[] | ||
public override Statistic[] LatestStatistics => new Statistic[] | ||
{ | ||
new Statistic("Total requests made", totalRequests), | ||
new Statistic("Requests which eventually succeeded", eventualSuccesses, Color.Green), | ||
new Statistic("Retries made to help achieve success", retries, Color.Yellow), | ||
new Statistic("Requests which eventually failed", eventualFailures, Color.Red), | ||
new("Total requests made", totalRequests), | ||
new("Requests which eventually succeeded", eventualSuccesses, Color.Green), | ||
new("Retries made to help achieve success", retries, Color.Yellow), | ||
new("Requests which eventually failed", eventualFailures, Color.Red), | ||
}; | ||
} | ||
} | ||
} |
Oops, something went wrong.