Что такое Polly?

Ответ

Polly — это библиотека для .NET, реализующая шаблоны устойчивости приложений (Resilience Patterns). Она позволяет элегантно обрабатывать временные сбои, ограничивать нагрузку и управлять временем выполнения операций.

Основные политики (Policies):

  1. Retry (Повторные попытки): Повторяет операцию при возникновении указанных исключений.
  2. Circuit Breaker (Автоматический выключатель): Временно блокирует выполнение операций при высокой частоте ошибок, чтобы дать удалённой системе восстановиться.
  3. Timeout (Таймаут): Прерывает выполнение операции, если она длится дольше заданного времени.
  4. Bulkhead (Переборка): Изолирует пулы ресурсов, чтобы сбой в одной части системы не исчерпал все ресурсы (например, все потоки).
  5. Fallback (Резервный вариант): Предоставляет альтернативное значение или действие при сбое.
  6. Cache (Кэширование): Кэширует результаты вызовов (требует отдельного пакета Polly.Caching).

Практический пример: Комбинирование Retry и Circuit Breaker для HTTP-вызова

using Polly;
using Polly.Extensions.Http;

// 1. Политика повторных попыток с экспоненциальной задержкой
var retryPolicy = HttpPolicyExtensions
    .HandleTransientHttpError() // Обрабатывает 5xx, 408, 502, 503, 504
    .WaitAndRetryAsync(3, retryAttempt => 
        TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); // Задержка: 2, 4, 8 сек.

// 2. Политика автоматического выключателя
var circuitBreakerPolicy = HttpPolicyExtensions
    .HandleTransientHttpError()
    .CircuitBreakerAsync(5, TimeSpan.FromSeconds(30)); // Размыкает цепь после 5 ошибок за 30 сек.

// 3. Объединение политик в стратегию
var resiliencePipeline = Policy.WrapAsync(retryPolicy, circuitBreakerPolicy);

// 4. Использование
await resiliencePipeline.ExecuteAsync(async () =>
{
    var response = await _httpClient.GetAsync("https://api.example.com/data");
    response.EnsureSuccessStatusCode();
    return await response.Content.ReadAsStringAsync();
});

Преимущества использования Polly:

  • Декларативный подход: Политики определяются отдельно от бизнес-логики.
  • Гибкость: Политики можно комбинировать и повторно использовать.
  • Асинхронная поддержка: Полная поддержка async/await.
  • Интеграция с IHttpClientFactory: Легко встраивается в конвейер обработки HTTP-запросов в ASP.NET Core.

Ответ 18+ 🔞

Смотри, есть такая библиотека Polly для .NET — она типа как бронежилет для твоего кода, когда он общается с внешним миром. Если что-то падает, глючит или тупит, она не даёт всему разъебаться моментально. Вместо этого включает мозги и пытается всё починить по уму.

Чем она умеет заниматься, эта умница:

  1. Retry (Повторять): Упала операция — ну ебнулось и ебнулось. А Polly возьмёт и попробует ещё разок, и ещё. Особенно если ошибка временная, типа сетевого глюка.
  2. Circuit Breaker (Предохранитель): Если ошибки посыпались как из ведра, она хлоп — и разрывает цепь. Перестаёт долбить удалённую систему, даёт ей отдышаться, а то ведь реально можно добить. Через время осторожно пробует снова.
  3. Timeout (Таймаут): Если операция зависла и думает дольше, чем тебе нужно, Polly её просто прервёт. Не будет ждать, пока все твои потоки упрутся в потолок.
  4. Bulkhead (Переборка): Это чтобы изолировать проблемы. Представь, что один сервис сдох и начал жрать все твои потоки. С этой политикой он сожрёт только свой выделенный лимит, а остальная система будет жить.
  5. Fallback (Запасной аэродром): Всё накрылось? Не беда. Можно вернуть какое-то дефолтное значение или выполнить простенькую резервную процедуру. Лишь бы пользователь не увидел жёлтый экран смерти.
  6. Cache (Кэш): Ну это если брать отдельный пакет — может запоминать результаты, чтобы не ходить за одним и тем же сто раз.

Вот как это может выглядеть в деле, когда нужно отправить HTTP-запрос и не сойти с ума:

using Polly;
using Polly.Extensions.Http;

// 1. Делаем политику повторных попыток. Упал запрос — ждём и пробуем снова.
var retryPolicy = HttpPolicyExtensions
    .HandleTransientHttpError() // Ловит временные ошибки вроде 500-х кодов или таймаутов
    .WaitAndRetryAsync(3, retryAttempt => 
        TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); // Ждём 2, потом 4, потом 8 секунд. Экспоненциальная back-off заебок.

// 2. Политика предохранителя. Если ошибок много, прекращаем пытаться нафиг.
var circuitBreakerPolicy = HttpPolicyExtensions
    .HandleTransientHttpError()
    .CircuitBreakerAsync(5, TimeSpan.FromSeconds(30)); // Если 5 ошибок подряд — разрываем цепь на 30 секунд.

// 3. Комбинируем эти две штуки в одну мощную стратегию.
var resiliencePipeline = Policy.WrapAsync(retryPolicy, circuitBreakerPolicy);

// 4. Используем эту банду.
await resiliencePipeline.ExecuteAsync(async () =>
{
    var response = await _httpClient.GetAsync("https://api.example.com/data");
    response.EnsureSuccessStatusCode(); // Если опять ошибка, политики вступят в игру.
    return await response.Content.ReadAsStringAsync();
});

И почему это вообще охуенно:

  • Всё красиво и отдельно: Ты описываешь правила устойчивости в одном месте, а бизнес-логика — в другом. Не превращается в спагетти-код.
  • Гибкость: Эти политики как лего — собираешь любую комбинацию под свою задачу.
  • Асинхронность: Всё работает нормально с async/await, не блокирует потоки.
  • Дружит с IHttpClientFactory: В ASP.NET Core встраивается в обработку HTTP-запросов буквально парой строк. Удобно, блядь.