0

There are several policy's that need to be the same throughout my code. For example:

var myIOProblems = Policy
  .Handle<IOException>()
  .WaitAndRetryForever(i => TimeSpan.FromSeconds(2));

Then I'll have some code that will do the work:

myIOProblems
    .Execute(() => otherPath.CopyTo(otherPathPart.FullName));

This works great, and I can litter the latter statements all over my code, change the behavior in one central place, and it all seems to work.

But in some places I need to provide the user/framework some feedback that problems are occurring. I can write a new policy:

Policy
    .Handle<IOException>()
    .WaitAndRetryForever(i => TimeSpan.FromSeconds(2), (e, t, c) =>
    {
        count++;
        statusUpdate.PCall($"Copying {otherPath.Name}: {other.Name} -> {Name} (retry ({count}): {e.Message})");
    })
    .Execute(() => otherPath.CopyTo(otherPathPart.FullName));

But now I've lost the ability to re-use common code. What I'd really like to be able to write is something like the following:

myIOProblems
    .OnRetry(e => statusUpdate.PCall($"Error ({e.Message}), retrying"))
    .Execute(() => otherPath.CopyTo(otherPathPart.FullName));

Or something similar to that. I may be overlooking something in the library, in which case I apologize!

Peter Csala
  • 17,736
  • 16
  • 35
  • 75
Gordon
  • 3,012
  • 2
  • 26
  • 35
  • Consider using `Execute()` overloads taking context data. You can use the same common policy, but supply different context data to `Execute()` at different call locations. The `onRetry` delegate receives this `Context` as a parameter, and can fork its behaviour accordingly. – mountain traveller Jan 27 '17 at 09:36
  • OnRetry above is something I made up - to demonstrate what I'd like to do. But, yeah, with the context, that will be fed to WaitAndRetryForever, and perhaps I can have a special functor in there that gets executed... – Gordon Jan 27 '17 at 20:16
  • I was referring to the `onRetry` delegate built into all Polly retry policies, rather than your made up `.OnRetry()`. In your first posted code example, the code `(e, t, c) => { ... }` is the `onRetry` delegate. The `c` input parameter you have there is the `Context`. This parameter `c` will be passed any context data you pass into an `Execute()` overload taking context data. So, you can use the same common policy, but vary `onRetry` behaviour by passing different context data to `Execute()` at different call locations. – mountain traveller Jan 27 '17 at 22:00
  • Do you want to update the caller each and every time when a retry attempt occur or only when all retry attempts have failed? – Peter Csala Oct 11 '22 at 09:42

1 Answers1

0

You can wrap your policy in a factory class and the getter function will optionally receive the onRetry callback:

public class PolicyFactory
{
    public static Policy GetMyPolicy(Action<Exception, TimeSpan, Context> onRetry = null)
    {
        return Policy
            .Handle<IOException>()
            .WaitAndRetryForever(i => TimeSpan.FromSeconds(2), onRetry);
    }
}
Marat Asadurian
  • 593
  • 1
  • 6
  • 18