question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Make the primary properties of the policies verifyable

See original GitHub issue

Please 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:

So I can’t make sure that the circuit break policy was set up correctly.



Proposals:

  1. Expose these fields as readonly properties to able to query them.
  2. Extend the interfaces (ITimeoutPolicy<T>, IRetryPolicy<T>, etc.) on which these properties are accessible
  3. Create a separate lib which is exposing only Verification helpers

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:4
  • Comments:12 (5 by maintainers)

github_iconTop GitHub Comments

2reactions
RichieRunnercommented, Aug 10, 2020

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.

1reaction
martintmkcommented, Jun 19, 2023

Any word on v8 progress?

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

Read more comments on GitHub >

github_iconTop 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 >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found