1

We have a listener that receives a message from a Service Bus queue and then sends the body to an API.

We use Polly for resilience in the cloud, namely the DecorrelatedJitterBackoffV2 policy.

Our concern with this policy is that we are unsure of how to calculate the maximum time that it could take to complete all retries, e.g. when medianFirstRetryDelay is set to 500ms and retryCount is set to 3.

This is important to us because of the message lock duration on the Service Bus queue. We want to ensure that the lock duration exceeds the time required to complete all retries.

Peter Csala
  • 17,736
  • 16
  • 35
  • 75
Alasdair Stark
  • 1,227
  • 11
  • 32
  • Not sure if this is possible at all. Apart from delays of consecutive retires, there are delays on net layer because of your API calls. And these are not easily measurable, depending on what client (http client or WCF client for example) your delays can be arbitrary (WCF client can be configured to wait for hours without throwing) – Wiktor Zychla Aug 17 '23 at 11:52
  • Yes, there will be delays that we cannot account for, however, we are just trying to understand if this particular timescale can be bounded – Alasdair Stark Aug 17 '23 at 14:40

1 Answers1

1

Retry

If you use DecorrelatedJitterBackoffV2 to generate the sleep durations then you can iterate through the result since it is an IEnumerable

IEnumerable<TimeSpan> delays = Backoff.DecorrelatedJitterBackoffV2(
    medianFirstRetryDelay: TimeSpan.FromMilliseconds(500),
    retryCount: 3);

foreach (var delay in delay) 
...

Please bear in mind that the generated TimeSpans can vary a lot between each method call.
I've generated five times the sequences and I've got these

[
   00:00:00.5042179,
   00:00:00.2196652,
   00:00:00.9364482
]

[
   00:00:00.5060196,
   00:00:00.8691744,
   00:00:00.8905491
]

[
   00:00:00.3786930,
   00:00:01.0092010,
   00:00:00.0805103
]

[
   00:00:00.6507813,
   00:00:00.1045026,
   00:00:00.9623235
]

[
   00:00:00.4164084,
   00:00:00.6975145,
   00:00:01.5628308
]

If you calculate the sum of the timespans in each sequence by delays.Select(t => t.TotalMilliseconds).Sum() then the results vary between 1.5 seconds and 2.5 seconds (usually).

Timeout

You can maximize each operation's duration by applying a local timeout policy on it.

Local in this context means the following:

  • The retry and the timeout policies are chained
  • The timeout is the inner and the retry is the outer
  • The retry triggers for the TimeoutRejectedException as well

Let's do the math

To calculate the worst case scenario you can do the following:

  • As we have seen the delays all together adds up in worst case 2.5 seconds
    • Let's round it to 3 seconds for the sake of simplicity
  • If you have local timeouts then you know how much time does it take (in worst case) for each attempt to fail
    • Since you set the retryCount to 3 that means you have 4 attempts (the initial call and the 3 retries)

If you set the timeout to 1.5 seconds that means it worst case it will finish in 9 seconds (4x 1.5seconds + 3seconds sleep).

Of course if you execute some time consuming code in the onTimeout or inside the onRetry then should add those to your calculation as well.

Peter Csala
  • 17,736
  • 16
  • 35
  • 75
  • Thanks Peter. Sorry, I should have mentioned that we also have a chained timeout of 3 seconds. Is there any guarantee that the worst case is 2.5 seconds or is it possible to know that? I guess I could iterate through the delays and put a ceiling on them to ensure that the total time never went above a certain amount. – Alasdair Stark Aug 17 '23 at 14:38
  • @AlasdairStark [Here](https://stackoverflow.com/a/75371425/13268855) I have shown an example how to cap the sleep durations. It could be easily altered to cap the overall sleep duration. If you wish I can edit my post later today to include that logic as well. – Peter Csala Aug 17 '23 at 15:03
  • 1
    Thanks. Sounds like there's no way to be 100% confident of the worst case so I'll cap the durations if we need to. – Alasdair Stark Aug 17 '23 at 16:12
  • 1
    @AlasdairStark [Here you can find the source code](https://github.com/Polly-Contrib/Polly.Contrib.WaitAndRetry/blob/master/src/Polly.Contrib.WaitAndRetry/Backoff.DecorrelatedJitterV2.cs#L35) for the timespan sequence generation. You could spending a couple of hours to understand how the values are generated ... or just simple cap it. :) – Peter Csala Aug 17 '23 at 19:28