I have the following method which has a retriable network call. The retry policy is specified for a specific exception.
public async Task<MyResponse> GetRecords(MyRequest request)
{
try
{
RetryPolicy retryPolicy = Policy.Handle<MyException>(ex => ex.ErrorCode == ErrorCode.MySpecificErrorCode)
.Retry(MAX_RETRY_COUNT, onRetry: (exception, retryCount) =>
{
log($"Retrying for {retryCount} times due to my error that I want to retry");
});
return await retryPolicy.Execute(async () =>
await OtherService.NetworkCall(request).ConfigureAwait(false))
.ConfigureAwait(false);
}
catch (Exception ex)
{
log(ex);
throw;
}
}
This is the unit test.
[TestMethod()]
public async Task TestRetry()
{
OtherServiceMock.SetupSequence(x => x.NetworkCall(It.IsAny<MyRequest>()))
.ThrowsAsync(new MyException(ErrorCode.MySpecificErrorCode, ExceptionMessage.MySpecificErrorMessage)) //this is getting thrown
.ThrowsAsync(new Exception());
MyRequest request = new MyRequest();
try
{
var response = await new MyClassMock.GetRecords(request).ConfigureAwait(false);
}
catch(Exception ex)
{
log("Event","Event");
}
}
The first exception is getting thrown instead of the second one. I have tweaked the max retry number, it didn't help. What am I doing wrong here?
CodePudding user response:
Just to make it clear, if you want to decorate a sync function with retry then you have to use one of the following policy builder methods:
Retry
,RetryForever
,WaitAndRetry
,WaitAndRetryForever
In this case the policy will be a RetryPolicy
, which implements the ISyncPolicy
interface. So, you can call the Execute
which is NOT awaitable.
If you want to decorate an async function with retry then you have to use one of the following policy builder methods:
RetryAsync
,RetryForeverAsync
,WaitAndRetryAsync
,WaitAndRetryForeverAsync
In this case the policy will be a AsyncRetryPolicy
, which implements the IAsyncPolicy
interface. So, you can call the ExecuteAsync
which is awaitable.
Here I have detailed how to choose between these method variants: https://stackoverflow.com/a/73095879/13268855
CodePudding user response:
Your mock setup is for x.GetRecord
OtherServiceMock.SetupSequence(x => x.GetRecord(It.IsAny<MyRequest>()))
.ThrowsAsync(new MyException(ErrorCode.MySpecificErrorCode, ExceptionMessage.MySpecificErrorMessage)) //this is getting thrown
.ThrowsAsync(new Exception());
But the part you want polly to retry on is OtherService.NetworkCall
return await retryPolicy.Execute(async () =>
await OtherService.NetworkCall(request).ConfigureAwait(false))
.ConfigureAwait(false);
Your SetupSequence should be mocking NetworkCall
OtherServiceMock.SetupSequence(x => x.NetworkCall(It.IsAny<MyRequest>()))
.ThrowsAsync(new MyException(ErrorCode.MySpecificErrorCode, ExceptionMessage.MySpecificErrorMessage)) //this is getting thrown
.ThrowsAsync(new Exception());