# Використовуючи Polly для відліків

# Введение

[Полі](https://www.pollydocs.org/) є вирішальним компонентом будь-якого . NET-розробника ' інструментарію M SK2 Це бібліотека, яка дозволяє вам визначити правила для використання винятків та повторів у вашій програмі *Я* використати Polly для обробки повторів у цій програмі.

<!--category-- Polly,ASP.NET,C# -->
<datetime class="hidden">2024-09-15T02:20</datetime>
[TOC]

# Полі

Полі справді добре справляється з цим. МСК0 - це не все, що вона може зробити. МSK1 - це справді інструментарій для додавання стійкості до ваших програм. . - Обидві способи підключення дозовні та внутрішнього зв 'язку

Вони взяті з [Поллі Strona główna](https://www.pollydocs.org/) і є основними шаблонами, які можна використовувати з Polly:

* Повторно спробувати: Знову спробувати, якщо щось не вийде . Це може бути корисним, коли проблема є тимчасовою і може зникнути
* Маршрутний розривник: Перестаньте пробувати, якщо щось зламано чи зайнятіM SK1 Це допоможе вам уникнути марнування часу і гіршого вигляду речей
* Timeout: Позбутись, якщо щось займає надто багато часуM SK1 Це може покращити вашу продуктивність, звільняючи простір та ресурси
* Оцінювач оцінок: Оцінювати кількість запити, які ви робите чи приймаєтеM SK1 Це дає вам змогу контролювати навантаження і запобігати проблемам або штрафам.
* Fallback: Зробіть щось інше, якщо щось не вийде
  Збереження: Робіть більше, ніж одну річ водночас і візьміть найшвидшу з нихM SK1 Це зробить вашу програму швидшою та більш чутливою

# Як я користуюсь Поллі

В цій програмі я користуюсь Polly в багатьох місцях.

## Служба перекладу на фоновому рівні

Для запуску мого перекладу та перевірки того, чи є доступні сервери EasyNMT. THSI дозволяє мені перевірити доступність сервісу перед запуском M SK1пропонувати' перекладу в моєму додатокіMST3 ВиM ST4 пам 'ятаєте, що це обидва [Мій редактор 'toyM SK1](/blog/backgroundtranslationspt3) для того, щоб ви могли перекладати позначку вниз і для мого ' в польотіM SK1 [блог пост переклад](/blog/usingfilebasedhybridblogging). Отже, це важливий момент. Я перевіряю, чи EasyNMT не знизився ' МSK3 і дозволяю чекати, поки він не підніметься МSK4 , що може зайняти декілька секунд

```csharp
 private async Task StartupHealthCheck(CancellationToken cancellationToken)
    {
        var retryPolicy = Policy
            .HandleResult<bool>(result => !result) // Retry when Ping returns false (service not available)
            .WaitAndRetryAsync(3, // Retry 3 times
                attempt => TimeSpan.FromSeconds(5), // Wait 5 seconds between retries
                (result, timeSpan, retryCount, context) =>
                {
                    logger.LogWarning("Translation service is not available, retrying attempt {RetryCount}", retryCount);
                });

        try
        {
            var isUp = await retryPolicy.ExecuteAsync(async () =>
            {
                return await Ping(cancellationToken); // Ping to check if the service is up
            });

            if (isUp)
            {
                logger.LogInformation("Translation service is available");
                TranslationServiceUp = true;
            }
            else
            {
                logger.LogError("Translation service is not available after retries");
                await HandleTranslationServiceFailure();
                TranslationServiceUp = false;
            }
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "An error occurred while checking the translation service availability");
            await HandleTranslationServiceFailure();
            TranslationServiceUp = false;
        }
    }
```

Тут ви бачите, що ми встановили концепцію Полі повторити спробу , яка повторить спробу 3 разів за один секундний відстанок між кожним повторенням спроби. `TranslationServiceUp` прапорець на фальшивий. Таким чином, будь-які послуги, які користуються перекладовою послугою, можуть знати, що він не доступнийM SK1

```mermaid
graph LR
    A[Start Health Check] --> B[Define Retry Policy]
    B --> C[Retry Policy: Retry 3 times]
    C --> D[Wait 5 seconds between retries]
    D --> E[Ping Translation Service]

    E --> F{Ping successful?}
    F -- Yes --> G[Log: Translation service is available]
    G --> H[Set TranslationServiceUp = true]

    F -- No --> I[Log: Translation service not available]
    I --> J[Check retry count]

    J -- Retry Limit Reached --> K[Log: Translation service not available after retries]
    K --> L[HandleTranslationServiceFailure]
    L --> M[Set TranslationServiceUp = false]

    J -- Retry Again --> E

    E --> N{Exception Occurs?}
    N -- Yes --> O[Log: Error occurred]
    O --> L

```

## Umami.Net

Я також використовую Polly у своїй Umami.Net-ліbraрії, щоб виконувати повторні спроби, коли я роблю запити в API Umami. . Це критична частина бібліотеки, тому що вона дозволяє мені вирішувати будь-які проблеми з API і повторювати запити, якщо це необхідно.

Ось я створив `HttpClient` для використання Policy Retry; в цьому випадку IM SK1m перевіряє `HttpStatusCode.ServiceUnavailable` і повторює запит, якщо він виникає. IM SK1m також використовуючи `Decorrelated Jitter Backoff` стратегію чекати між повторами. Це хороша стратегія, яку можна використати, бо вона допомагає уникнути проблеми, коли всі клієнти повторюють спробу в один і той же час. M SK3 незважаючи на те, що це \ '\ - це тільки я \ МSK5\. Це може допомогти зменшити завантаження на сервері та підвищити шанси, що запити будуть успішними.

```csharp
     var httpClientBuilder = services.AddHttpClient<AuthService>(options =>
            {
                options.BaseAddress = new Uri(umamiSettings.UmamiPath);
            })
            .SetHandlerLifetime(TimeSpan.FromMinutes(5)) 
            .AddPolicyHandler(RetryPolicyExtension.GetRetryPolicy());


    public static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
    {
        var delay = Backoff.DecorrelatedJitterBackoffV2(TimeSpan.FromSeconds(1), 3);
        return HttpPolicyExtensions
            .HandleTransientHttpError()
            .OrResult(msg => msg.StatusCode == HttpStatusCode.ServiceUnavailable)
            .WaitAndRetryAsync(delay);
    }
```

Використовуючи політику повторного спробування `HttpClient` запити є важливим способом покращення надійності. Хоча ми любимо думати, що наші веб-сервіси завжди доступні там 's always SOME downtime МSK2in my case when for example [Вежба](https://github.com/containrrr/watchtower) виявляє, що закінчується оновлення, і перезапускає контейнер Umami). Таким чином, якщо у вас є політика повторного спроби, то це допоможе вам впевнитись, що ваша програма може легко справлятися з такими ситуаціями

## FileSystemWatcher

Ще одна річ, яку я користуюся Polly - це коли працюю з завантаженням та збереженням файлів в моєму програмі. Я використовую `FileSystemWatcher` для моніторингу папки, де зберігаються мої відміткові файли. Коли файл створюється або оновується, я завантажую його і оброблюю . Це може стати проблемою, якщо файл все ще записується до того часу, коли відбувається триггеруванняM SK2 Тому я використовую `RetryPolicy` для вирішення цієї ситуації.

Тут ви бачите, що я керую `IOException` що викидається, коли файл використовується і повторює операцію. Я використовую `WaitAndRetryAsync` policy для повторного спробування операції 5 разів з затримкою між кожним повторним спробуваннямM SK1 Це дозволяє мені справлятися з ситуацією, коли файл все ще записується, і повторювати операцію допоки він не закінчиться

Найважливішим тут є те, що я кидаю `IOException` від мого `SavePost` метод, який дозволяє політиці Поллі керувати повторним випробуванням. Це хороший шаблон, який слід слідкувати, оскільки він дозволяє керувати логікою повторного випробування в центральному місці і не обов 'язково турбуватися про нього у кожній методиці, яка може потребувати повторного виконання операції.

В цілому **завжди керувати винятками, коли ви можете** і **кидати** на вищий рівень, де ви можете працювати з ними більш централізовано. ( або записувати їх в журналі

```csharp
      private async Task OnChangedAsync(WaitForChangedResult e)
    {
       ...
        var retryPolicy = Policy
            .Handle<IOException>() // Only handle IO exceptions (like file in use)
            .WaitAndRetryAsync(5, retryAttempt => TimeSpan.FromMilliseconds(500 * retryAttempt),
                (exception, timeSpan, retryCount, context) =>
                {
                    activity?.Activity?.SetTag("Retry Attempt", retryCount);
                    // Log the retry attempt
                    logger.LogWarning("File is in use, retrying attempt {RetryCount} after {TimeSpan}", retryCount,
                        timeSpan);
                });

      ...

            // Use the Polly retry policy for executing the operation
            await retryPolicy.ExecuteAsync(async () =>
            {
              ...
                var blogService = scope.ServiceProvider.GetRequiredService<IBlogService>();
                await blogService.SavePost(blogModel);
               ...
            });
...
    }
```

Знову ж таки, це приклад мого коду, який взаємодіє з зовнішньою послугою, в цьому випадку - з файловою системою . Там, де я Враховую певні типи помилок, які трапляютьсяM SK2 Я також записую їх за допомогою [Серілогобстеження](/blog/selfhostingseqpt2) який надсилає їх Seq, який тоді надсилить мені електронну пошту, коли errror зареєструється, щоб я міг визначити будь-які проблеми, які могли б виникнути.

Знову ж таки, , загальною концепцією є справлятися з винятками, де можна , записувати їх, коли це можливо МSK2t і впевнитись, що у вас є спосіб дізнатися, що відбувається | ' | МSK4 | Це може допомогти переконатися, що ваша програма стійка до змін та здатна справлятись з будь-якими проблемами, які можуть виникнути

## Служба електронної пошти

У моєму сервісі електронної пошти я використовую `CircuitBreaker` шаблон і правила повторного спробування. Правила повторного пробування використовуються для того, щоб розв 'язати проблему, коли електронні листи недоступні, а блокатор схеми використовується для розв' язання проблеми, коли електронний лист зайнятий або переповнений

Обидві з них важливі в випадку з е-мейлами; SMTP - відносно повільний і потенційно ненадійний протокол

Тут я управляю SMtpExceptions, де, коли виникає помилка з SMTP-сервісу, він спочатку повторює спробу тричі з затримкою між кожним повторенням . Якщо служба ще не доступна після репетицій МSK2 і ще два для нового відправлення M SK3 блокатор схеми відкриється і припинить відправляти електронні листи на хвилину . Це може допомогти запобігти надмірному навантаженням електронної служби MSC5 та заблокуванню мого konta МSK6 і підвищити шанси успішного відправлення електронної листи MST7

```csharp
         // Initialize the retry policy
            var retryPolicy = Policy
                .Handle<SmtpException>() // Retry on any exception
                .WaitAndRetryAsync(3, // Retry 3 times
                    attempt => TimeSpan.FromSeconds(2 * attempt),
                    (exception, timeSpan, retryCount, context) =>
                    {
                        logger.LogWarning(exception, "Retry {RetryCount} for sending email failed", retryCount);
                    });

            // Initialize the circuit breaker policy
            var circuitBreakerPolicy = Policy
                .Handle<SmtpException>()
                .CircuitBreakerAsync(
                    5,
                    TimeSpan.FromMinutes(1), 
                    onBreak: (exception, timespan) =>
                    {
                        logger.LogError("Circuit broken due to too many failures. Breaking for {BreakDuration}", timespan);
                    },
                    onReset: () =>
                    {
                        logger.LogInformation("Circuit reset. Resuming email delivery.");
                    },
                    onHalfOpen: () =>
                    {
                        logger.LogInformation("Circuit in half-open state. Testing connection...");
                    });
            _policyWrap = Policy.WrapAsync(retryPolicy, circuitBreakerPolicy);
            
            
```

Потім це використовується в циклі відсилання електронної пошти, який чекає, щоб нові повідомлення були додані до каналу, а потім намагається їх надіслати.

Це використовує всю конфігураційність у policy, щоб додати гнучкість до процесу відправлення електронної листи.

```csharp
 while (await _mailMessages.Reader.WaitToReadAsync(token))
        {
            BaseEmailModel? message = null;
            try
            {
                message = await _mailMessages.Reader.ReadAsync(token);

                // Execute retry policy and circuit breaker around the email sending logic
                await _policyWrap.ExecuteAsync(async () =>
                {
                    switch (message)
                    {
                        case ContactEmailModel contactEmailModel:
                            await _emailService.SendContactEmail(contactEmailModel);
                            break;
                        case CommentEmailModel commentEmailModel:
                            await _emailService.SendCommentEmail(commentEmailModel);
                            break;
                    }
                });

                _logger.LogInformation("Email from {SenderEmail} sent", message.SenderEmail);
            }
            catch (OperationCanceledException)
            {
                break;
            }
            catch (Exception exc)
            {
                _logger.LogError(exc, "Couldn't send an e-mail from {SenderEmail}", message?.SenderEmail);
            }
        }
```

# На завершення

Поллі - це потужна бібліотека, яка може допомогти вам додати стійкість до ваших програм. Використовуючи Polly, ви можете справлятися з ретриями , блокаторами схем МSK2 відхиленням часу M SK3 обмеженнями швидкості , падіннями та хеджуванням в вашій програмі MSC5 Це допоможе вам бути впевненим у тому, що ваша програма надійна і здатна справлятись з будь-якими проблемами, які можуть виникнути
В цьому пості я насправді лише розповідав про один аспект Polly; ретрийів, це механізм, який може покращити гнучкість і надійність вашої програми . Використовуючи Polly ви можете впоратися з ретриями в послідовний спосіб та переконатись, що ваша програма може справлятися з будь-якими проблемами, які можуть виникнути M SK3