Back to "Pollyn käyttäminen kostotoimiin"

This is a viewer only at the moment see the article on how this works.

To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk

This is a preview from the server running through my markdig pipeline

ASP.NET C# Polly

Pollyn käyttäminen kostotoimiin

Sunday, 15 September 2024

Johdanto

Polly on kriittinen osa minkä tahansa.NET-kehittäjän työkalupakkia. Se on kirjasto, jonka avulla voit määritellä käytännöt poikkeusten käsittelyä ja palautuksia varten hakemuksessasi. Tässä artikkelissa tutkimme, miten Minä käytä Pollya retriittien käsittelyyn tässä sovelluksessa.

Polly

Vaikka Polly retisee todella hyvin, se ei ole kaikki, mitä se voi tehdä, se on todella työkalupakki, joka lisää sietokykyä sovelluksiisi. Sekä puhelut ulkopuolisille palveluille että sisäisesti.

Nämä on otettu Polly pääsivu ja ovat tärkeimmät kuviot, joita voit käyttää Pollyn kanssa:

  • Yritä uudelleen, jos jokin epäonnistuu. Tästä voi olla hyötyä, kun ongelma on väliaikainen ja voi hävitä.
  • Circuit Breaker: Lopeta yrittäminen, jos jokin on rikki tai kiireinen. Tämä voi hyödyttää sinua välttämällä ajan tuhlaamista ja pahentamalla tilannetta. Se voi myös tukea järjestelmän elpymistä.
  • Aikalisä: Luovuta, jos jokin vie liian kauan. Tämä voi parantaa suorituskykyäsi vapauttamalla tilaa ja resursseja.
  • Rate Limiter: Rajaa, kuinka monta pyyntöä teet tai hyväksyt. Näin voit hallita kuormaa ja ehkäistä ongelmia tai rangaistuksia.
  • Varaisku: Tee jotain muuta, jos jokin epäonnistuu. Tämä voi parantaa käyttökokemustasi ja pitää ohjelman toiminnassa. Suojaus: Tee useampi kuin yksi asia yhtä aikaa ja ota nopein. Tämä voi tehdä ohjelmastasi nopeamman ja reagoivamman.

Miten käytän Pollya

Tässä sovelluksessa käytän Pollya useissa paikoissa.

Taustakäännöspalvelu

Käännöspalveluni käynnistämiseen ja EasyNMT-palvelimien tarkistamiseen on saatavilla tietoa. Voit tarkistaa, että palvelu on saatavilla, ennen kuin alat "tarjota" käännöspalvelua sovelluksessani. Muistat varmaan, että tätä molempia käytetään päätoimittajani "lelu" Jotta voit kääntää maalin alas ja minun "on the fly" blogikirjoitus käännöskone...................................................................................................................................... Joten on tärkeää, että tarkistan, ettei EasyNMT ole laskenut (ja mahdollistanut odottamisen, kunnes se nousee, mikä voi kestää muutaman sekunnin).

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

Tässä näet, että olemme laatineet Polly Retry -käytännön, joka yrittää uudelleen kolme kertaa viiden sekunnin odottelulla jokaisen retryn välillä. Jos palvelua ei ole vielä saatavilla retriittien jälkeen, kirjaudumme sisään virheestä ja hoidamme vian asettamalla TranslationServiceUp lippu väärälle. Tämä antaa kaikille käännöspalvelua käyttäville palveluille mahdollisuuden tietää, että sitä ei ole saatavilla.

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

Käytän Pollya myös Umamissani.Net-kirjastossa retriittien käsittelyyn, kun teen pyyntöjä Umamin sovellusrajapintaan. Tämä on kriittinen osa kirjastoa, koska sen avulla voin käsitellä API:n ongelmia ja tarvittaessa kokeilla pyyntöä uudelleen.

Tähän pystytin omani HttpClient Käyttää Retrice Policy; Tässä tapauksessa olen tarkistamassa, että HttpStatusCode.ServiceUnavailable ja yrittää uudelleen pyyntöä, jos se tapahtuu. Käytän myös Decorrelated Jitter Backoff strategia odottaa retriittien välissä. Tätä strategiaa on hyvä käyttää, koska se auttaa välttämään "lumoavan lauman" ongelman, jossa kaikki asiakkaat yrittävät samaan aikaan uudelleen (vaikka se onkin vain minä :)). Tämä voi auttaa vähentämään palvelimen kuormitusta ja parantaa pyynnön onnistumisen mahdollisuuksia.

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

Uusintakäytännön käyttäminen HttpClient Pyynnöt ovat tärkeä tapa parantaa luotettavuutta. Vaikka haluamme ajatella, että nettipalvelumme ovat aina saatavilla, aina on jonkin verran vapaa-aikaa (minun tapauksessani, kun esimerkiksi Vartiotorni Havaitsee päivityksen olevan kesken ja käynnistää uudelleen Umamin astian). Uusintakäytäntö voi siis auttaa varmistamaan, että sovelluksesi pystyy hoitamaan nämä tilanteet sulavasti.

TiedostoSystemWatcher

Toinen käyttö, jota käytän Pollyyn, on tiedostojen lataaminen ja tallentaminen sovellukseeni. Käytän FileSystemWatcher Seurataksesi hakemistoa, johon marchdown-tiedostoni tallennetaan. Kun tiedosto luodaan tai päivitetään, lataan tiedoston ja käsittelen sen. Tämä voi olla ongelma, jos tiedosto kirjoitetaan vielä tapahtuman käynnistyessä. Joten käytän RetryPolicy hoitamaan tätä tilannetta.

Tässä näet, minä hoidan tämän. IOException se heitetään, kun tiedosto on käytössä ja kokeillaan uudelleen operaatiota. Käytän WaitAndRetryAsync linjaus, jonka mukaan operaatiota yritetään uudelleen viisi kertaa viivyttelemällä kunkin yrityksen välillä. Näin voin hoitaa tilanteen, jossa tiedostolle kirjoitetaan ja sitä yritetään uudelleen, kunnes se onnistuu.

Kriittistä tässä on se, että oksennan IOException Omalta SavePost Menetelmä, jonka avulla Polly-politiikka voi hoitaa uudelleenyrittämisen. Tämä on hyvä malli noudattaa, koska sen avulla voit käsitellä uudelleenyrittämisen logiikkaa keskeisessä paikassa, eikä sinun tarvitse huolehtia siitä kaikissa menetelmissä, jotka saattavat tarvita uudelleenyrittämistä.

Yleisesti ottaen käsittele poikkeukset aina siellä, missä voit sekä oksenna Korkeammalle tasolle, jossa voit käsitellä niitä keskitetymmin (tai kirjata ne). Tämä voi auttaa vähentämään koodin monimutkaisuutta ja helpottaa poikkeusten käsittelyä johdonmukaisella tavalla.

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

Tämä on jälleen esimerkki koodini vuorovaikutuksesta ulkopuolisen palvelun, tässä tapauksessa tiedostojärjestelmän, kanssa. Jossa ODOTAN, että tapahtuu tiettyjä virhetyyppejä. Kirjaan nämä myös muistiin SerilogTracing joka lähettää ne Seqille, joka sitten lähettää minulle sähköpostia, kun erehtyjä on kirjautunut, jotta voin tunnistaa mahdolliset ongelmat.

Yleisnäkemyksenä on jälleen käsitellä poikkeuksia siellä, missä voi, kirjata ne silloin, kun ei voi ja varmistaa, että tietää, mitä tapahtuu. Tämä voi auttaa varmistamaan, että sovelluksesi on kestävä ja kestää kaikki mahdolliset ongelmat.

Sähköpostipalvelu

Sähköpostipalvelussani käytän molempia CircuitBreaker kuvio ja uusintapolitiikka. Uudelleenyrittämiskäytäntöä käytetään jutussa, jossa sähköpostipalvelua ei ole saatavilla ja virrankatkaisijaa käytetään käsittelemään tapausta, jossa sähköpostipalvelu on varattu tai ylikuormitettu.

Molemmat ovat tärkeitä sähköpostien osalta; SMTP on suhteellisen hidas ja mahdollisesti epäluotettava protokolla.

Tässä käsittelen SmtpExceptions-järjestelmää, jossa SMTP-palvelusta tulevan virheen jälkeen se yrittää ensin uudelleen kolme kertaa viiveellä jokaisen uudelleenyrittämisen välillä. Jos palvelua ei ole vielä saatavilla retriittien jälkeen (ja vielä kaksi uutta lähetystä varten), virrankatkaisija aukeaa ja lopettaa sähköpostien lähettämisen hetkeksi. Tämä voi auttaa estämään sähköpostipalvelun ylikuormituksen (ja tilini sulkemisen) ja parantaa sähköpostin onnistumisen mahdollisuuksia.

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

Tätä käytetään sitten sähköpostilähetyksessäni, joka odottaa uusien viestien lisäämistä kanavalle ja yrittää lähettää niitä.

Tämä käyttää kaiken funktioanliteetin käytännössä lisätäkseen sietokykyä sähköpostin lähetysprosessiin.

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

Johtopäätöksenä

Polly on tehokas kirjasto, joka voi auttaa sinua lisäämään sietokykyä sovelluksiisi. Käyttämällä Pollya voit käsitellä retries-, virtapiirinkatkaisimet, aikakatkaisut, nopeusrajoittimet, varaiskut ja suojaukset sovelluksessasi. Tämä voi auttaa varmistamaan, että sovelluksesi on luotettava ja että se pystyy käsittelemään mahdolliset ongelmat. Tässä viestissä todella käsittelin vain yhtä Pollyn näkökulmaa; retries, nämä ovat mekanismi, joka voi parantaa sovelluksesi sietokykyä ja luotettavuutta. Käyttämällä Pollya voit käsitellä retriikkejä johdonmukaisesti ja varmistaa, että sovelluksesi pystyy käsittelemään mahdolliset ongelmat.

logo

©2024 Scott Galloway