我们有一个 Windows Azure 函数,我们将 Polly 实现为 -
public async Task<T> ExecuteTaskWithRetryAsync<T>(int maxRetryAttempts, int delayBetweenFirstRetryInSeconds, string invocationIdentifier, Func<Task<T>> function)
{
logger.LogInformation($"Executing {invocationIdentifier} with retries.");
var retryPolicy = Policy
.Handle<HttpRequestException>(ex => ex.StatusCode != HttpStatusCode.BadRequest && ex.StatusCode != HttpStatusCode.Unauthorized)
.WaitAndRetryAsync(
maxRetryAttempts,
retryAttempt => TimeSpan.FromSeconds(delayBetweenFirstRetryInSeconds * Math.Pow(2, retryAttempt - 1)),
(exception, timeSpan, retryCount, context) =>
{
logger.LogWarning("Execution of {identifier} failed. Waiting {sec} seconds before retry. Attempt number {retryCount}. Exception - {exceptionMessage}", invocationIdentifier, timeSpan.Seconds, retryCount, exception.Message);
});
return await retryPolicy.ExecuteAsync<T>(async () =>
{
T result = await function();
logger.LogInformation($"Successfully executed {invocationIdentifier}");
return result;
});
并被用作
var response = await retryService.ExecuteTaskWithRetryAsync(retryOptions.MaxRetryAttempts, retryOptions.DelayBetweenRetriesInSeconds, nameof(GetFromMetaRPAsync), async () =>
{
return await httpClient.GetAsync(endpoint).ConfigureAwait(false);
});
if (!response.IsSuccessStatusCode)
{
throw new HttpRequestException($"Failed to retrieve any results. Response with status code {response?.StatusCode} - {response?.ReasonPhrase}.");
}
但是在App Insights中,我们只能看到初始日志
“重试执行 {invocableIdentifier}”
然后抛出
HttpRequestException
,状态代码为 504 (GatewayTimeout)。
我可以看到一个开放问题,其中讨论了 Polly 重试未记录为单独的依赖项,但他们能够看到重试日志。我们甚至看不到
的重试日志“重试前等待 {sec} 秒。”
当服务器出现问题时,例如BadGateway、GatewayTimeout等
但是,我们能够间歇性地看到此日志行
“重试前等待 {sec} 秒...异常 - 发送请求时出错”。
在未捕获重试的情况下,我们将在大约 10 秒后收到调用的响应。 20秒。重试是否有可能在内部发生,但 App Insights 没有捕获?即使没有依赖项,是否仍应捕获重试日志? 我们如何验证重试是否确实发生?
我们已经在本地运行了代码,并且还进行了单元测试,在这两种情况下,我们都可以看到正在发生的重试。云上的行为会有所不同吗?
仅当装饰的HttpClient
抛出
HttpRequestException
时,您的重试策略才会触发:
.Handle<HttpRequestException>(...
这意味着如果您的
HttpClient
没有抛出 HRE 异常,但确实返回带有 504 状态代码的 HttpResponseMessage
那么您的重试逻辑将不会被触发。
您可能会观察到网关超时的
HttpRequestException
,因为在策略执行后,您的代码会执行成功检查
if (!response.IsSuccessStatusCode)
{
throw new HttpRequestException($"Failed to retrieve any results. Response with status code {response?.StatusCode} - {response?.ReasonPhrase}.");
}
EnsureSuccessStatusCode
方法。
var response = await retryService.ExecuteTaskWithRetryAsync(retryOptions.MaxRetryAttempts, retryOptions.DelayBetweenRetriesInSeconds, nameof(GetFromMetaRPAsync), async () =>
{
var httpResponse = await httpClient.GetAsync(endpoint).ConfigureAwait(false);
httpResponse.EnsureSuccessStatusCode();
return httpResponse;
});
正如您在 dotnet 源代码中看到的那样,可能抛出的 HRE 包含状态代码以及原因短语。
定义您的策略以触发
HttpResponseMessage
var retryPolicy = Policy
.Handle<HttpRequestException>(ex => ex.StatusCode != HttpStatusCode.BadRequest && ex.StatusCode != HttpStatusCode.Unauthorized)
.OrResult<HttpResponseMessage>(res => res.StatusCode != HttpStatusCode.BadRequest && res.StatusCode != HttpStatusCode.Unauthorized)
.WaitAndRetryAsync(...
或
var nonRetryableStatusCodes = [ HttpStatusCode.BadRequest, HttpStatusCode.Unauthorized];
...
var retryPolicy = Policy
.Handle<HttpRequestException>(ex => nonRetryableStatusCodes.Contains(ex.StatusCode) is false)
.OrResult<HttpResponseMessage>(res => nonRetryableStatusCodes.Contains(res.StatusCode) is false)
.WaitAndRetryAsync(