У меня есть API .NET 8, использующий Polly для обеспечения устойчивости к внешним службам, таким как Azure SQL и Microsoft Graph. Моя текущая реализация использует пользовательские политики повтора и автоматического выключателя, как показано ниже:
PollyExtensions.cs:
public static class PollyExtensions
{
public static AsyncRetryPolicy CreateRetryPolicy(this ILogger logger, string infraService)
{
var delay = Backoff.DecorrelatedJitterBackoffV2(medianFirstRetryDelay: TimeSpan.FromSeconds(1), retryCount: 5);
return Policy
.Handle<SqlException>()
.Or<Exception>()
.Or<TimeoutException>()
.WaitAndRetryAsync(delay,
onRetry: (exception, timespan, retryAttempt, context) =>
{
logger.LogWarning(exception, "Error talking to {infraService}, Error: {Message}, will retry after {timeSpan}. Retry attempt {retryCount} ",
infraService, exception.Message, timespan, retryAttempt);
});
}
public static AsyncCircuitBreakerPolicy CreateCircuitBreakerPolicy()
{
return Policy
.Handle<Exception>()
.CircuitBreakerAsync(
exceptionsAllowedBeforeBreaking: 5,
durationOfBreak: TimeSpan.FromMinutes(1)
);
}
}
Изучая новые функции .NET 8, я наткнулся на AddStandardResilienceHandler
и AddStandardHedgingHandler
для реализации устойчивости.
Использованная литература :
https://devblogs.microsoft.com/dotnet/building-resilient-cloud-services-with-dotnet-8/
https://juliocasal.com/blog/Building-Microservices-With-Dotnet-8
Может ли кто-нибудь предоставить примеры кода, демонстрирующие, как использовать AddStandardResilienceHandler и AddStandardHedgingHandler в контексте моего класса GraphSvcClient для вызовов внешних зависимостей?
Есть ли какие-либо особые соображения при использовании этих новых функций по сравнению с настраиваемыми политиками?
ГрафСвкклиент.cs
public sealed class GraphSvcClient(ICacheProvider cacheProvider,
IAzureAuthTokenService azureAuthTokenService,
ILogger<GraphSvcClient> logger) : IGraphSvcClient
{
private readonly ICacheProvider _cacheProvider = cacheProvider.IsNotNull();
private readonly IAzureAuthTokenService _azureAuthTokenService = azureAuthTokenService.IsNotNull();
private readonly ILogger<GraphSvcClient> _logger = logger.IsNotNull();
/// <summary>
/// Get Microsoft Graph graphClient
/// </summary>
/// <returns></returns>
public async Task<GraphServiceClient> GetGraphServiceClientAsync()
{
var accessToken = await GetAccessTokenAsync();
var retryPolicy = _logger.CreateRetryPolicy(infraService: "MicrosoftGraph");
var circuitBreakerPolicy = PollyExtensions.CreateCircuitBreakerPolicy();
var combinedPolicy = Policy.WrapAsync(retryPolicy, circuitBreakerPolicy);
var graphServiceClient = await combinedPolicy.ExecuteAsync(async () =>
{
var client = new GraphServiceClient(new DelegateAuthenticationProvider(async (req) =>
{
req.Headers.Authorization = new AuthenticationHeaderValue(JwtBearerDefaults.AuthenticationScheme, accessToken);
await Task.CompletedTask;
}));
return client;
});
return graphServiceClient;
}
}
Я рассматриваю возможность обновления Polly и связанных с ним пакетов nuget до последних совместимых версий, чтобы использовать новейшие функции .NET 8.
Список пакетов Nuget, использованных в проекте:
<PackageReference Include = "Polly" Version = "7.2.4" />
<PackageReference Include = "Polly.Contrib.WaitAndRetry" Version = "1.1.1" />
<PackageReference Include = "Microsoft.Extensions.Http.Polly" Version = "8.0.0" />
Я вижу некоторые недоразумения, поэтому позвольте мне попытаться прояснить ситуацию.
Microsoft.Extensions.Http.XYZ
пакетыPolly по своей конструкции не зависит от предметной области. Другими словами, его можно использовать для обработки временных ошибок, связанных с HTTP-вызовами, а также для математических расчетов. Политики (в случае V7) достаточно универсальны, чтобы их можно было использовать в самых разных случаях.
Одним из распространенных вариантов использования является сетевое общение на основе HttpClient
. Из-за его популярности сначала сообщество Polly, а затем Microsoft выпустило несколько вспомогательных структур и методов, упрощающих интеграцию и использование Polly с помощью HttpClient
.
Для API V7 Microsoft выпустила Microsoft.Extensions.Http.Polly
, который помогает вам оборудовать все HttpClient
вызовы произвольными политиками устойчивости с помощью метода расширения AddPolicyHandler
.
Для API V8 Microsoft выпустила пакет Microsoft.Extensions.Http.Resilience, который помогает вам украшать все вызовы HttpClient
либо предопределенными конвейерами устойчивости, либо любыми произвольными стратегиями устойчивости. Первое можно сделать с помощью методов расширения AddStandardResilienceHandler
, AddStandardHedgingHandler
, а второе — с помощью AddResilienceHandler
.
Вашу стратегию повторных попыток можно легко перенести в V8. К счастью, алгоритм экспоненциальной отсрочки поддерживается изначально. Это означает, что вам не нужно полагаться на какую-то зависимость от вклада.
return new ResiliencePipelineBuilder().AddRetry(new()
{
ShouldHandle = new PredicateBuilder()
.Handle<SqlException>()
.Handle<TimeoutException>()
.Handle<Exception>(),
BackoffType = DelayBackoffType.Exponential,
UseJitter = true,
MaxRetryAttempts = 5,
Delay = TimeSpan.FromSeconds(1),
OnRetry = args =>
{
logger...
return default;
}
})
.Build();
Обратите внимание: если у вас есть предложение Handle<Exception>
/Or<Exception>
в случае V7 или предложение Handle<Exception>
в случае V8, то все остальные предложения Handle
/Or
не обязательны.
Короче говоря, вы не можете перенести это как есть. Вам необходимо использовать подход, основанный на выборке , если вы хотите использовать API V8.
Объединение нескольких политик в API V7 можно выполнить несколькими способами, но предложенным решением было использование Policy.Wrap{Async}
.
В случае с V8 вам нужно использовать ResiliencePipelineBuilder
, чтобы добавить несколько стратегий в свой конвейер.
ResiliencePipeline pipeline = new ResiliencePipelineBuilder()
.AddRetry(new()
{
...
})
.AddCircuitBreaker(new()
{
...
})
.Build();
В случае V8 порядок регистрации также важен, как и в случае с V7.
Ваши исходные политики не были связаны с HTTP. Ваши стратегии V8 также не обязательно должны быть связаны с HTTP. Это означает, что использование AddStandardResilienceHandler
или AddStandardHedgingHandler
не требуется.
Основываясь на общем фрагменте кода, я не могу сказать, является ли GraphServiceClient
типизированным HttpClient
или нет (но я предполагаю, что это не так). Итак, вам просто нужно перенести политики повторных попыток и прерывания цепи в V8, чтобы иметь возможность использовать все преимущества V8.
Большое спасибо @Peter Csala за ваш ответ. Я очень ценю детали, представленные здесь, которые мне очень помогут.