← Назад к вопросам

Что такое Polly?

1.2 Junior🔥 141 комментариев
#Основы C# и .NET

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое Polly?

Polly — это мощная библиотека для .NET, предназначенная для реализации стратегий устойчивости (resilience) и обработки временных сбоев (transient fault handling) в распределенных системах и микросервисах. Она предоставляет разработчикам набор готовых политик (policies), которые позволяют приложениям элегантно и эффективно справляться с неизбежными проблемами, возникающими в реальных условиях: сбоями сети, временными ошибками сервисов, высокой нагрузкой и т.д. Основная философия Polly заключается в том, чтобы не просто обрабатывать исключения, а управлять поведением системы при их возникновении, повышая её надежность и отказоустойчивость.

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

Polly предлагает несколько ключевых типов политик, которые можно комбинировать для создания сложных стратегий устойчивости.

1. Повтор (Retry)

Эта политика автоматически повторяет выполнение операции при возникновении определенного исключения. Это особенно полезно для временных сбоев (например, временная потеря связи с базой данных или внешним API).

// Пример политики Retry: повторять 3 раза при любом исключении
var retryPolicy = Policy
    .Handle<Exception>()
    .Retry(3, onRetry: (exception, retryCount) =>
    {
        Console.WriteLine($"Попытка {retryCount} завершилась ошибкой: {exception.Message}");
    });

// Использование
retryPolicy.Execute(() =>
{
    // Код, который может вызвать временный сбой (например, вызов API)
    CallExternalService();
});

2. Ожидание (Wait and Retry)

Более продвинутая версия повтора, которая добавляет паузы между попытками (например, экспоненциально увеличивающиеся интервалы), чтобы избежать перегрузки целевого сервиса.

// Ожидание с экспоненциальной задержкой
var waitAndRetryPolicy = Policy
    .Handle<HttpRequestException>()
    .WaitAndRetry(
        3,
        retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
        onRetry: (exception, timeSpan, retryCount, context) =>
        {
            Console.WriteLine($"Попытка {retryCount} после ожидания {timeSpan.TotalSeconds} сек.");
        }
    );

3. Разрыв цепи (Circuit Breaker)

Эта политика реализует паттерн «Разрыв цепи» (Circuit Breaker), который предотвращает «заклинивание» системы при постоянных сбоях. Если ошибки происходят слишком часто, цепь «разрывается» (переходит в состояние Open), и дальнейшие попытки выполнения блокируются на определенное время, позволяя системе восстановиться.

var circuitBreakerPolicy = Policy
    .Handle<TimeoutException>()
    .CircuitBreaker(
        exceptionsAllowedBeforeBreaking: 2,
        durationOfBreak: TimeSpan.FromSeconds(30),
        onBreak: (exception, state, timeSpan, context) =>
        {
            Console.WriteLine($"Цепь разорвана! Блокировка на {timeSpan.TotalSeconds} сек.");
        },
        onReset: (context) => Console.WriteLine("Цепь восстановлена!")
    );

4. Тайм-аут (Timeout)

Политика гарантирует, что операция не будет выполняться бесконечно, устанавливая максимальное время её выполнения.

var timeoutPolicy = Policy.TimeoutAsync(
    TimeSpan.FromSeconds(5),
    TimeoutStrategy.Optimistic,
    onTimeoutAsync: (context, timeSpan, task, exception) =>
    {
        Console.WriteLine($"Операция превысила лимит времени {timeSpan.TotalSeconds} сек.");
        return Task.CompletedTask;
    }
);

5. Откат (Fallback)

Предоставляет альтернативное действие или значение, если основная операция завершилась неудачно. Это позволяет системе сохранять функциональность даже при сбоях.

var fallbackPolicy = Policy
    .Handle<Exception>()
    .Fallback(() =>
    {
        Console.WriteLine("Основная операция не удалась, выполняется откат.");
        return "Значение отката";
    });

var result = fallbackPolicy.Execute(() =>
{
    // Основная логика, которая может сломаться
    throw new Exception("Ошибка!");
});

6. Комбинирование политик (PolicyWrap)

Polly позволяет объединять несколько политик в одну, создавая комплексные стратегии. Например, можно создать политику, которая сначала пытается повторить операцию несколько раз с ожиданием, но если сбои продолжаются, разрывает цепь и затем предоставляет значение отката.

var compositePolicy = Policy.Wrap(
    fallbackPolicy,
    circuitBreakerPolicy,
    waitAndRetryPolicy
);

Почему Polly критически важна для Backend-разработки на C#?

  • Микросервисная архитектура: В системах, состоящих из множества взаимодействующих сервисов, временные сбои неизбежны. Polly позволяет каждому сервису устойчиво реагировать на проблемы соседей.
  • Работа с внешними зависимостями: Вызовы API, базы данных, очереди сообщений — все это может временно недоступно. Стратегии повтора и разрыва цепи предотвращают лавинообразное распространение ошибок.
  • Контроль времени ответа: Политика тайм-аута гарантирует, что медленный ответ одного компонента не заблокирует всю систему.
  • Деградация функциональности: Откат позволяет системе, даже в условиях частичного отказа, предоставлять базовые функции или контент, улучшая пользовательский опыт.
  • Конфигурируемость и тестируемость: Политики легко настраиваются и могут быть инъектированы через DI, что соответствует современным практикам разработки.

Пример реального использования

Рассмотрим типичный сценарий вызова внешнего HTTP API с использованием нескольких политик Polly:

using Polly;
using Polly.Timeout;
using System.Net.Http;

public class ResilientApiClient
{
    private readonly HttpClient _client;
    private readonly IAsyncPolicy<HttpResponseMessage> _resiliencePolicy;

    public ResilientApiClient()
    {
        _client = new HttpClient();

        // Создаем комбинированную политику: Тайм-аут -> Повтор с ожиданием -> Разрыв цепи
        _resiliencePolicy = Policy.TimeoutAsync<HttpResponseMessage>(TimeSpan.FromSeconds(10))
            .WrapAsync(Policy<HttpResponseMessage>
                .Handle<HttpRequestException>()
                .OrResult(r => !r.IsSuccessStatusCode)
                .WaitAndRetryAsync(
                    3,
                    retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))
                ))
            .WrapAsync(Policy<HttpResponseMessage>
                .Handle<HttpRequestException>()
                .OrResult(r => !r.IsSuccessStatusCode)
                .CircuitBreakerAsync(
                    5,
                    TimeSpan.FromSeconds(30)
                ));
    }

    public async Task<string> GetDataResiliently(string url)
    {
        return await _resiliencePolicy.ExecuteAsync(async () =>
        {
            var response = await _client.GetAsync(url);
            return await response.Content.ReadAsStringAsync();
        });
    }
}

В этом примере политика гарантирует, что вызов API будет:

  1. Прерван, если превысит 10 секунд.
  2. Повторен до 3 раз с экспоненциальным увеличением задержки при ошибках сети или неудачных статус-кодах.
  3. Блокирован на 30 секунд, если 5 последовательных попыток завершились неудачей (Circuit Breaker).

Polly является не просто библиотекой, а фундаментальным инструментом для создания устойчивых (resilient) и производственных (production-ready) backend-систем на C#. Она воплощает в код принципы, описанные в паттернах устойчивости, и позволяет разработчикам сосредоточиться на бизнес-логике, делегируя сложные сценарии обработки сбоев стандартизированным, проверенным стратегиям.