Make the primary properties of the policies verifyable
See original GitHub issuePlease make it possible to verify policies’ main properties.
Let’s suppose I want to create a combined policy where I want to put together a Retry, Circuit Breaker and Timeout policies to surround my HttpClients.
The configuration class:
public class HttpResilienceSettings
{
public int TimeoutInMilliseconds { get; set; }
public int RetrySleepInMilliseconds { get; set; }
public int RetryCount { get; set; }
public int CircuitBreakerFailCount { get; set; }
public int CircuitBreakerDelayInMilliseconds { get; set; }
}
The initialization of the policy registry:
public class HttpResiliencePolicies
{
public const string RequestRetryPolicy = "RetryPolicy";
public const string RequestTimeoutPolicy = "TimeoutPolicy";
public const string RequestCircuitBreakerPolicy = "CircuitBreakerPolicy";
public const string CombinedPolicy = "Retry-CircuitBreaker-Timeout";
public PolicyRegistry InitializePolicies(HttpResilienceSettings settings)
=> new PolicyRegistry
{
{ RequestTimeoutPolicy, TimeoutPolicy(settings) },
{ RequestCircuitBreakerPolicy, CircuitBreakerPolicy(settings) },
{ RequestRetryPolicy, RetryPolicy(settings) },
{ CombinedPolicy, Policy.WrapAsync(RetryPolicy(settings), CircuitBreakerPolicy(settings), TimeoutPolicy(settings))}
};
private IAsyncPolicy<HttpResponseMessage> TimeoutPolicy(HttpResilienceSettings settings)
=> Policy
.TimeoutAsync<HttpResponseMessage>(
timeout: TimeSpan.FromMilliseconds(settings.TimeoutInMilliseconds));
private IAsyncPolicy<HttpResponseMessage> CircuitBreakerPolicy(HttpResilienceSettings settings)
=> HttpPolicyExtensions
.HandleTransientHttpError()
.Or<TimeoutRejectedException>()
.CircuitBreakerAsync(
handledEventsAllowedBeforeBreaking: settings.CircuitBreakerFailCount,
durationOfBreak: TimeSpan.FromMilliseconds(settings.CircuitBreakerDelayInMilliseconds));
private IAsyncPolicy<HttpResponseMessage> RetryPolicy(HttpResilienceSettings settings)
=> Policy
.Handle<BrokenCircuitException>()
.Or<TimeoutRejectedException>()
.Or<HttpRequestException>()
.WaitAndRetryAsync(
retryCount: settings.RetryCount,
sleepDurationProvider: _ => TimeSpan.FromMilliseconds(settings.RetrySleepInMilliseconds))
.AsAsyncPolicy<HttpResponseMessage>();
}
I want to be able to catch these sort of issues:
- sleepDurationProvider: _ => TimeSpan.FromSeconds(settings.RetrySleepInMilliseconds)
- sleepDurationProvider: _ => TimeSpan.FromMilliseconds(settings.RetrySleepInMilliseconds) + 2000
- sleepDurationProvider: _ => TimeSpan.FromSeconds(settings.TimeoutInMilliseconds)
Current solution: If I want to test for example the Timeout policy’s Timeout then I can do something like this:
[Fact]
public async Task HttpResiliencePolicies_TimeoutPolicy_Set_Timeout_Property()
{
//Arrange
const int ExpectedTimeoutMS = 1234;
var httpPolicies = new HttpResiliencePolicies();
PolicyRegistry registry = null;
HttpResilienceSettings settings = GenerateSettings(timeoutMS: ExpectedTimeoutMS);
//REF: https://github.com/App-vNext/Polly/blob/ffe99a34edd96d5c5c94075fe22aae8e1a7ed3ed/src/Polly/Timeout/AsyncTimeoutPolicy.cs#L53
const string timeoutProviderFieldName = "_timeoutProvider";
//Act
registry = httpPolicies.InitializePolicies(settings);
//Assert
var timeoutPolicy = registry[HttpResiliencePolicies.RequestTimeoutPolicy] as AsyncTimeoutPolicy<HttpResponseMessage>;
Func<Context, TimeSpan> timeoutProvider = GetPrivateFieldValue <AsyncTimeoutPolicy<HttpResponseMessage>, Func<Context, TimeSpan>>
(timeoutProviderFieldName, timeoutPolicy);
//Pretend that the operation succeeded under the given timeframe / constraint
var policyExecutionResult = await timeoutPolicy.ExecuteAndCaptureAsync(
() => Task.FromResult(new HttpResponseMessage()));
var actualTimeSpan = timeoutProvider.Invoke(policyExecutionResult.Context);
Assert.Equal(ExpectedTimeoutMS, actualTimeSpan.TotalMilliseconds);
}
Helpers:
private HttpResilienceSettings GenerateSettings(
int timeoutMS = 1,
int sleepDurationMS = 1, int retryCount = 1, //retry
int failureCount = 1, int delayDurationMS = 1) //circuit breaker
=> new HttpResilienceSettings
{
TimeoutInMilliseconds = timeoutMS,
RetrySleepInMilliseconds = sleepDurationMS,
RetryCount = retryCount,
CircuitBreakerFailCount = failureCount,
CircuitBreakerDelayInMilliseconds = delayDurationMS,
};
private TFieldValue GetPrivateFieldValue<TPolicy, TFieldValue>(string fieldName, TPolicy actualInstance)
where TPolicy : IAsyncPolicy<HttpResponseMessage>
where TFieldValue : class
=> actualInstance.GetType()
.GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance)
.GetValue(actualInstance) as TFieldValue;
As you can see I highly rely on the actual implementation in order to be able to verify it. To make thing worst, I can do this sort of sorcery only for the following properties:
- Timeout’s Timeout: _timeoutProvider
- Retry’s RetryCount: _permittedRetryCount
- Retry’s SleepDuration: _sleepDurationsEnumerable
So I can’t make sure that the circuit break policy was set up correctly.
Proposals:
- Expose these fields as readonly properties to able to query them.
- Extend the interfaces (ITimeoutPolicy<T>, IRetryPolicy<T>, etc.) on which these properties are accessible
- Create a separate lib which is exposing only Verification helpers
Issue Analytics
- State:
- Created 4 years ago
- Reactions:4
- Comments:12 (5 by maintainers)
Top Results From Across the Web
Verifiable Credentials Data Model v1.1
A set of one or more claims made by an issuer. A verifiable credential is a tamper-evident credential that has authorship that can...
Read more >Verifiable Credentials Data Model v2.0
Verifiable credentials represent statements made by an issuer in a tamper-evident and privacy-respecting manner. Holders can assemble collections of verifiable ...
Read more >Duo Administration - Policy & Control
Duo's Policy & Control feature enable centralized settings management. ... To do this: Navigate to an application's properties page in the Duo Admin...
Read more >Qualitative Characteristics of Accounting Information
Qualitative characteristics of accounting information that impact how useful the information is: Verifiability; Timeliness; Understandability ...
Read more >What are risks in Azure AD Identity Protection
Unfamiliar sign-in properties, Real-time, Premium ; Malicious IP address, Offline, Premium ; Suspicious inbox manipulation rules, Offline, Premium.
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
I’d also like to see this; for the purpose of unit testing that my initialization of Polly was done correctly and the right configurations for my policy was set.
V8 alpha is released where the validation is addressed.
Check the new package: https://www.nuget.org/packages/Polly.Core/
And samples: https://github.com/App-vNext/Polly/tree/main/samples
cc @martincostello