# Використання ввічливих рецидивів

# Вступ

[ПолліCity in Alaska USA (optional, probably does not need a translation)](https://www.pollydocs.org/) є критичною частиною набору інструментів розробника.NET. Це бібліотека, яка надає вам змогу визначати правила роботи з винятками і повтореннями у вашій програмі. У цій статті ми дослідимо, як це робити. *I* використовувати для обробки повторень у цій програмі.

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

# ПолліCity in Alaska USA (optional, probably does not need a translation)

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

Вони взяті з [Основна сторінка Polly](https://www.pollydocs.org/) і є основними шаблонами, які ви можете використовувати за допомогою Polly:

* Спробуйте ще раз, якщо щось не вийде. Це може бути корисним, якщо проблема тимчасова і може зникнути.
* Brought Breaker: Stop try if something are breaked or bused. Це допоможе тобі не марнувати часу і не погіршувати ситуацію. Вона також може підтримувати систему відновлення.
* Тайм- аут: здайтеся, якщо щось займає надто багато часу. Це може поліпшити вашу продуктивність, вивільняючи простір і ресурси.
* Обмеження швидкості: Обмежити кількість запитів, які ви виконуєте або приймаєте. Це допоможе тобі контролювати тягар і запобігати проблемам та покаранням.
* Повернення: роби щось інше, якщо щось не вийде. Це може покращити ваш досвід користувача і змусити програму працювати.
  Роби декілька речей одночасно і найшвидше. Завдяки цьому ваша програма стане швидшою і більш чуйною.

# Як я користуюся поліцією

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

## BackgroundTranslateServiceName

Для запуску служби перекладу і перевірки серверів EasyNMT доступні. Thsi дозволяє мені перевірити, що сервіс доступний перед тим, як почати "пропонувати" перекладацьку службу в моєму додатку. Ви пам'ятаєте, що це обидва використовується для [Мій редактор " іграшкова"](/blog/backgroundtranslationspt3) щоб ви могли перекласти відмітку на мою "на муху" [Рушій перекладу блогу](/blog/usingfilebasedhybridblogging). Отже, це критично. Я перевіряю, що EasyNMT не зменшився (і вмикання очікування до того часу, коли воно прийде; що може тривати декілька секунд).

```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 рази з 5 секунд очікування між кожною спробою. Якщо службу після спроб служби не буде знайдено, ми вестимемо запис про помилку і оброблятимемо помилку за допомогою параметра `TranslationServiceUp` flag to false. Тоді будь - які служби, які використовують перекладацьку службу, знають, що вона недоступна.

```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

А ещё я использую Полли в моей библиотеке "Уамами.Net," чтобы уладить сделки, когда высылаю приглашения в API Umami. Це критична частина бібліотеки, яка дозволяє мені впоратися з будь-якими проблемами з API і повторити запит, якщо потрібно.

Ось мій. `HttpClient` для використання правила повторення; у цьому випадку я перевіряю на `HttpStatusCode.ServiceUnavailable` і повторила спробу запиту, якщо це сталося. Я також використовую a `Decorrelated Jitter Backoff` Стратегія очікування між рецидивами. Це добра стратегія, яку слід використовувати, щоб уникнути проблеми "розподілу," де всі клієнти знову намагаються одночасно (хоча це тільки я:). За допомогою цього пункту можна зменшити навантаження на сервер і збільшити ймовірність успішного надсилання запиту.

```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` Просьба є важливим способом поліпшення надійності. Хоча нам подобається думати, що наші веб-служби завжди доступні, завжди є деяке скорочення (в моєму випадку, коли, наприклад, [Вартова Башта](https://github.com/containrrr/watchtower) визначає пріоритет оновлення і перезапускає контейнер Umami). Отже, якщо ви будете дотримуватись політики повторення, це допоможе вам з приємністю справлятися з такими ситуаціями.

## FileSystemWatcher

Ще одне використання, яке я роблю з Polly, це коли йдеться про завантаження і збереження файлів у моїй програмі. I use a `FileSystemWatcher` для спостереження за каталогом, у якому зберігаються мої файли markdown. Під час створення або оновлення файла я завантажую файл і обробляти його. Це може бути проблемою, якщо файл все ще буде записано під час вмикання події. Тож я використовую a `RetryPolicy` чтобы справиться с этой ситуацией.

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

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

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

```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);
               ...
            });
...
    }
```

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

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

## emailServiceComment

У своїй поштовій службі я користуюся обома `CircuitBreaker` Візерунок і правила повторення. Правила повторення використовуються для роботи з службами електронної пошти, де служби електронної пошти недоступні, а також для роботи з районним вимикачом, коли служба електронної пошти зайнята або перенавантаження.

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

Тут я розробляю SmtpExcodings, де, коли з служби SMTP приходять помилки, спочатку буде повторено три рази з затримкою між кожною спробою. Якщо після повторних спроб (і ще два для нового надсилання) служби не буде знайдено, засіб для пересилання районного зв' язку на хвилину відкриє і припинить відсилання електронних листів. За допомогою цього пункту ви можете запобігти перевантаження служби електронної пошти (і заблокуванню мого облікового запису) та удосконалити шанси успішного надсилання повідомлення електронної пошти.

```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);
            
            
```

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

Для цього в процесі відправки електронної пошти використовується все, що пов'язане з фантіоантулію, щоб додати стійкості до процесу відсилання повідомлень електронної пошти.

```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);
            }
        }
```

# Включення

Поллі - це могутня бібліотека, яка може допомогти вам додати гнучкості до ваших програм. За допомогою поліцій ви можете керувати розкладами, переривами, тайм- аудиторією, обмеженням швидкості, поверненням назад і зверненням до вашої програми. Це допоможе вам переконатися, що ваше застосування надійне і може розв'язати будь - які проблеми.
У цьому пості я дійсно тільки що охоплює один аспект Поллі; звернення, це механізм, який може покращити стійкість і надійність вашого застосування. Якщо ви користуєтесь поліцією, то зможете послідовно впоратися з картами і переконатися, що ваша програма вирішить будь - які проблеми.