Polly 回退操作没有抛出指定的异常。发生了什么?
Polly fallback action did not throw the specified exception. What happened?
鉴于此代码尝试调用 AuthenticationManager.Authenticate()
10 次,然后在 10 次尝试失败后抛出 CustomException
:
string res = Policy
.Handle<Exception>() // Handles any exception
.OrResult<string>(result => string.IsNullOrWhiteSpace(result)) // or if result is null
.Fallback(() => throw new CustomException("Exception!")) // Not being thrown after 10 unsuccessful attempts
.Wrap(
Policy
.Handle<Exception>()
.OrResult<string>(result => string.IsNullOrWhiteSpace(result))
.WaitAndRetry(
10,
retryAttempt => TimeSpan.FromSeconds(60),
onRetry: (response, delay, retryCount, context) => Trace.WriteLine($"[{DateTime.UtcNow}] Authentication failed. Retrying after 60 seconds...(Attempt {retryCount} of 10)")))
.ExecuteAndCapture(() => AuthenticationManager.Authenticate())
.Result;
为什么 CustomException
没有从回退操作中抛出?正确的做法应该是什么?
这些单元测试通过:(xUnit)
[Fact]
public void Test1()
{
var policy = Policy<string>
.Handle<Exception>()
.OrResult(result => string.IsNullOrWhiteSpace(result))
.Fallback(() => throw new CustomException())
.Wrap(
Policy<string>
.Handle<Exception>()
.OrResult(result => string.IsNullOrWhiteSpace(result))
.WaitAndRetry(
10,
_ => TimeSpan.FromSeconds(1),
onRetry: (response, delay, retryCount, context) => Trace.WriteLine($"[{DateTime.UtcNow}] Authentication failed. Retrying after 1 second...(Attempt {retryCount} of 10)")
)
);
var result = policy.ExecuteAndCapture(() => throw new Exception("Muh"));
Assert.IsType<CustomException>(result.FinalException);
Assert.Null(result.Result);
Assert.Equal(OutcomeType.Failure, result.Outcome);
}
[Fact]
public void Test2()
{
var policy = Policy<string>
.Handle<Exception>()
.OrResult(result => string.IsNullOrWhiteSpace(result))
.Fallback(() => throw new CustomException())
.Wrap(
Policy<string>
.Handle<Exception>()
.OrResult(result => string.IsNullOrWhiteSpace(result))
.WaitAndRetry(
10,
_ => TimeSpan.FromSeconds(1),
onRetry: (response, delay, retryCount, context) => Trace.WriteLine($"[{DateTime.UtcNow}] Authentication failed. Retrying after 1 second...(Attempt {retryCount} of 10)")
)
);
Assert.Throws<CustomException>(() => policy.Execute(() => throw new Exception("Muh")));
}
所以,我想,您可以只使用 Execute
,或者像这样检查结果并重新抛出异常:
var result = policy.ExecuteAndCapture(() => AuthenticationManager.Authenticate());
if( result.Outcome == OutcomeType.Failure && result.FinalException is not null)
{
throw result.FinalException;
}
return result.Result;
发现仅使用 WaitAndRetry
并检查 Outcome
对我有用(以防有人遇到这个问题):
var policyResult = Policy
.Handle<Exception>()
.OrResult<AuthenticationResult>(result => result is null)
.WaitAndRetry(
10,
retryAttempt => TimeSpan.FromSeconds(60),
onRetry: (response, delay, retryCount, context) => Trace.WriteLine($"[{DateTime.UtcNow}] Call failed. Retrying after 60 seconds...(Attempt {retryCount} of 10)"))
.ExecuteAndCapture(() => AuthenticationManager.Authenticate());
if (policyResult.Outcome == OutcomeType.Failure)
{
throw new CustomException("FAILED", policyResult.FinalException);
}
else
{
string value = policyResult.FinalHandledResult;
}
鉴于此代码尝试调用 AuthenticationManager.Authenticate()
10 次,然后在 10 次尝试失败后抛出 CustomException
:
string res = Policy
.Handle<Exception>() // Handles any exception
.OrResult<string>(result => string.IsNullOrWhiteSpace(result)) // or if result is null
.Fallback(() => throw new CustomException("Exception!")) // Not being thrown after 10 unsuccessful attempts
.Wrap(
Policy
.Handle<Exception>()
.OrResult<string>(result => string.IsNullOrWhiteSpace(result))
.WaitAndRetry(
10,
retryAttempt => TimeSpan.FromSeconds(60),
onRetry: (response, delay, retryCount, context) => Trace.WriteLine($"[{DateTime.UtcNow}] Authentication failed. Retrying after 60 seconds...(Attempt {retryCount} of 10)")))
.ExecuteAndCapture(() => AuthenticationManager.Authenticate())
.Result;
为什么 CustomException
没有从回退操作中抛出?正确的做法应该是什么?
这些单元测试通过:(xUnit)
[Fact]
public void Test1()
{
var policy = Policy<string>
.Handle<Exception>()
.OrResult(result => string.IsNullOrWhiteSpace(result))
.Fallback(() => throw new CustomException())
.Wrap(
Policy<string>
.Handle<Exception>()
.OrResult(result => string.IsNullOrWhiteSpace(result))
.WaitAndRetry(
10,
_ => TimeSpan.FromSeconds(1),
onRetry: (response, delay, retryCount, context) => Trace.WriteLine($"[{DateTime.UtcNow}] Authentication failed. Retrying after 1 second...(Attempt {retryCount} of 10)")
)
);
var result = policy.ExecuteAndCapture(() => throw new Exception("Muh"));
Assert.IsType<CustomException>(result.FinalException);
Assert.Null(result.Result);
Assert.Equal(OutcomeType.Failure, result.Outcome);
}
[Fact]
public void Test2()
{
var policy = Policy<string>
.Handle<Exception>()
.OrResult(result => string.IsNullOrWhiteSpace(result))
.Fallback(() => throw new CustomException())
.Wrap(
Policy<string>
.Handle<Exception>()
.OrResult(result => string.IsNullOrWhiteSpace(result))
.WaitAndRetry(
10,
_ => TimeSpan.FromSeconds(1),
onRetry: (response, delay, retryCount, context) => Trace.WriteLine($"[{DateTime.UtcNow}] Authentication failed. Retrying after 1 second...(Attempt {retryCount} of 10)")
)
);
Assert.Throws<CustomException>(() => policy.Execute(() => throw new Exception("Muh")));
}
所以,我想,您可以只使用 Execute
,或者像这样检查结果并重新抛出异常:
var result = policy.ExecuteAndCapture(() => AuthenticationManager.Authenticate());
if( result.Outcome == OutcomeType.Failure && result.FinalException is not null)
{
throw result.FinalException;
}
return result.Result;
发现仅使用 WaitAndRetry
并检查 Outcome
对我有用(以防有人遇到这个问题):
var policyResult = Policy
.Handle<Exception>()
.OrResult<AuthenticationResult>(result => result is null)
.WaitAndRetry(
10,
retryAttempt => TimeSpan.FromSeconds(60),
onRetry: (response, delay, retryCount, context) => Trace.WriteLine($"[{DateTime.UtcNow}] Call failed. Retrying after 60 seconds...(Attempt {retryCount} of 10)"))
.ExecuteAndCapture(() => AuthenticationManager.Authenticate());
if (policyResult.Outcome == OutcomeType.Failure)
{
throw new CustomException("FAILED", policyResult.FinalException);
}
else
{
string value = policyResult.FinalHandledResult;
}