C# 中用于工作流的 Polly 模式?
Polly patterns in C# for a workflow?
我的工作流程是这样的:
- 调用一个API方法
- 如果抛出任何异常但超时,程序会记录该异常并抛出它。
- 如果超时,程序必须调用另一个 API 方法。
- 调用另一个API方法后,如果一切正常,程序returns一个结果。
- 否则程序抛出异常并记录。
两种 API 方法具有相同类型的结果。
我想用 polly 策略来实现这个。
这是我的示例代码:
var retryPolicy = Policy
.Handle<HttpRequestException>(ex => ex.StatusCode == HttpStatusCode.RequestTimeout)
.RetryAsync(1, async (exception, retryCount) =>
await CallAnotherAPI());
var fallbackPolicy = Policy<HttpResponseMessage>
.Handle<Exception>()
.FallbackAsync((r, c, ct) => throw r.Exception,
async (r, c) =>
{
Log(r.Message);
});
var result = await fallbackPolicy
.WrapAsync(retryPolicy)
.ExecuteAsync(async () =>
{
await CallAPI();
});
但它不起作用,并且一直执行 fallbackPolicy。怎么写retryPolicy为true不执行fallbackPolicy的代码?
如果我正确理解了您的工作流程,那么您根本不需要重试政策。回退政策就足够了。
所以,假设 CallApi
和 CallAnotherApi
是这样实现的:
private static HttpClient client = new HttpClient();
public static async Task<HttpResponseMessage> CallAPI()
{
return await client.GetAsync("http://httpstat.us//408");
}
public static async Task<HttpResponseMessage> CallAnotherAPI()
{
var response = await client.GetAsync("http://httpstat.us//500");
response.EnsureSuccessStatusCode();
return response;
}
- 我已经使用
httpstatus.us
来模拟某些 http 状态代码
CallApi
总是会因请求超时而失败
CallAnotherApi
将始终抛出 HttpRequestException
因为 Ensure
方法调用
现在让我们看看策略定义和用法:
public static async Task Main(string[] args)
{
var fallbackPolicy = Policy<HttpResponseMessage>
.HandleResult(msg => msg.StatusCode == HttpStatusCode.RequestTimeout)
.FallbackAsync(async (_) => await CallAnotherAPI());
HttpResponseMessage result;
try
{
result = await fallbackPolicy
.ExecuteAsync(async () =>
{
return await CallAPI();
});
}
catch (Exception ex) {
Console.WriteLine(ex.Message); //TODO: replace with logging
throw;
}
Console.WriteLine(result.StatusCode);
}
- 仅当响应的状态代码为 408 时才应触发回退策略
如果 CallApi
或 CallAnotherApi
抛出 ,ExecuteAsync
将抛出异常
让我们逐一看看不同的场景
CallApi
成功
public static async Task<HttpResponseMessage> CallAPI()
{
return await client.GetAsync("http://httpstat.us//200");
}
输出
OK
CallApi
失败
public static async Task<HttpResponseMessage> CallAPI()
{
var response = await client.GetAsync("http://httpstat.us//500");
response.EnsureSuccessStatusCode();
return response;
}
输出
Response status code does not indicate success: 500 (Internal Server Error).
然后应用程序因为throw;
而崩溃
CallApi
超时,CallAnotherApi
成功
public static async Task<HttpResponseMessage> CallAPI()
{
return await client.GetAsync("http://httpstat.us//408");
}
public static async Task<HttpResponseMessage> CallAnotherAPI()
{
var response = await client.GetAsync("http://httpstat.us//200");
response.EnsureSuccessStatusCode();
return response;
}
输出
OK
CallApi
超时和 CallAnotherApi
失败
public static async Task<HttpResponseMessage> CallAPI()
{
return await client.GetAsync("http://httpstat.us//408");
}
public static async Task<HttpResponseMessage> CallAnotherAPI()
{
var response = await client.GetAsync("http://httpstat.us//500");
response.EnsureSuccessStatusCode();
return response;
}
输出
Response status code does not indicate success: 500 (Internal Server Error).
然后应用程序因为throw;
而崩溃
在这种情况下,polly 回退就足够了。像这样....
var fallbackPolicy = Policy<HttpResponseMessage>
.Handle<Exception>()
.FallbackAsync((r, c, ct) => throw r.Exception,
async (r, c) =>
{
Log(r.Message);
});
我的工作流程是这样的:
- 调用一个API方法
- 如果抛出任何异常但超时,程序会记录该异常并抛出它。
- 如果超时,程序必须调用另一个 API 方法。
- 调用另一个API方法后,如果一切正常,程序returns一个结果。
- 否则程序抛出异常并记录。
两种 API 方法具有相同类型的结果。 我想用 polly 策略来实现这个。
这是我的示例代码:
var retryPolicy = Policy
.Handle<HttpRequestException>(ex => ex.StatusCode == HttpStatusCode.RequestTimeout)
.RetryAsync(1, async (exception, retryCount) =>
await CallAnotherAPI());
var fallbackPolicy = Policy<HttpResponseMessage>
.Handle<Exception>()
.FallbackAsync((r, c, ct) => throw r.Exception,
async (r, c) =>
{
Log(r.Message);
});
var result = await fallbackPolicy
.WrapAsync(retryPolicy)
.ExecuteAsync(async () =>
{
await CallAPI();
});
但它不起作用,并且一直执行 fallbackPolicy。怎么写retryPolicy为true不执行fallbackPolicy的代码?
如果我正确理解了您的工作流程,那么您根本不需要重试政策。回退政策就足够了。
所以,假设 CallApi
和 CallAnotherApi
是这样实现的:
private static HttpClient client = new HttpClient();
public static async Task<HttpResponseMessage> CallAPI()
{
return await client.GetAsync("http://httpstat.us//408");
}
public static async Task<HttpResponseMessage> CallAnotherAPI()
{
var response = await client.GetAsync("http://httpstat.us//500");
response.EnsureSuccessStatusCode();
return response;
}
- 我已经使用
httpstatus.us
来模拟某些 http 状态代码 CallApi
总是会因请求超时而失败CallAnotherApi
将始终抛出HttpRequestException
因为Ensure
方法调用
现在让我们看看策略定义和用法:
public static async Task Main(string[] args)
{
var fallbackPolicy = Policy<HttpResponseMessage>
.HandleResult(msg => msg.StatusCode == HttpStatusCode.RequestTimeout)
.FallbackAsync(async (_) => await CallAnotherAPI());
HttpResponseMessage result;
try
{
result = await fallbackPolicy
.ExecuteAsync(async () =>
{
return await CallAPI();
});
}
catch (Exception ex) {
Console.WriteLine(ex.Message); //TODO: replace with logging
throw;
}
Console.WriteLine(result.StatusCode);
}
- 仅当响应的状态代码为 408 时才应触发回退策略 如果
ExecuteAsync
将抛出异常
CallApi
或 CallAnotherApi
抛出 ,让我们逐一看看不同的场景
CallApi
成功
public static async Task<HttpResponseMessage> CallAPI()
{
return await client.GetAsync("http://httpstat.us//200");
}
输出
OK
CallApi
失败
public static async Task<HttpResponseMessage> CallAPI()
{
var response = await client.GetAsync("http://httpstat.us//500");
response.EnsureSuccessStatusCode();
return response;
}
输出
Response status code does not indicate success: 500 (Internal Server Error).
然后应用程序因为throw;
CallApi
超时,CallAnotherApi
成功
public static async Task<HttpResponseMessage> CallAPI()
{
return await client.GetAsync("http://httpstat.us//408");
}
public static async Task<HttpResponseMessage> CallAnotherAPI()
{
var response = await client.GetAsync("http://httpstat.us//200");
response.EnsureSuccessStatusCode();
return response;
}
输出
OK
CallApi
超时和 CallAnotherApi
失败
public static async Task<HttpResponseMessage> CallAPI()
{
return await client.GetAsync("http://httpstat.us//408");
}
public static async Task<HttpResponseMessage> CallAnotherAPI()
{
var response = await client.GetAsync("http://httpstat.us//500");
response.EnsureSuccessStatusCode();
return response;
}
输出
Response status code does not indicate success: 500 (Internal Server Error).
然后应用程序因为throw;
在这种情况下,polly 回退就足够了。像这样....
var fallbackPolicy = Policy<HttpResponseMessage>
.Handle<Exception>()
.FallbackAsync((r, c, ct) => throw r.Exception,
async (r, c) =>
{
Log(r.Message);
});