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
Polly is een cruciaal onderdeel van een.NET ontwikkelaar toolkit. Het is een bibliotheek die u toelaat om beleid vast te stellen voor de behandeling van uitzonderingen en herhalingen in uw toepassing. In dit artikel zullen we onderzoeken hoe I Polly gebruiken om retrieves in deze toepassing te verwerken.
Terwijl Polly doet opnieuw echt goed het is niet alles wat het kan doen, het is echt een toolkit voor het toevoegen van veerkracht aan uw toepassingen. Beiden bellen naar externe diensten en intern.
Deze zijn afkomstig uit de Hoofdpagina van Polly en zijn de belangrijkste patronen die u kunt gebruiken met Polly:
In deze toepassing gebruik ik Polly op meerdere plaatsen.
Voor het opstarten van mijn vertaaldienst en het controleren van de EasyNMT servers zijn beschikbaar. Thsi stelt me in staat om de dienst te controleren is beschikbaar voordat u begint met het 'bieden' van de vertaaldienst in mijn app. Je zult je herinneren dat dit beide wordt gebruikt voor mijn editor'speelgoed' om je in staat te stellen markdown te vertalen en voor mijn 'on the fly' blog post vertaling engine. Het is dus belangrijk dat ik controleer of EasyNMT niet naar beneden is gegaan (en laat wachten tot het komt; dat kan een paar seconden duren).
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;
}
}
Hier kunt u zien dat we een Polly Retry beleid dat zal opnieuw proberen 3 keer met een 5-seconde wachten tussen elke retry. Als de service nog steeds niet beschikbaar is na de retrieves, loggen we een foutmelding en verwerken we de fout door het instellen van de TranslationServiceUp
De vlag is vals. Hierdoor kunnen alle diensten die gebruik maken van de vertaaldienst weten dat het niet beschikbaar is.
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
Ik gebruik Polly ook in mijn Umami.Net bibliotheek om retrieves af te handelen bij het maken van verzoeken aan de Umami API. Dit is een cruciaal onderdeel van de bibliotheek, omdat ik hiermee eventuele problemen met de API kan oplossen en indien nodig het verzoek opnieuw kan proberen.
Hier heb ik mijn HttpClient
om een Retry Policy te gebruiken; in dit geval controleer ik voor een HttpStatusCode.ServiceUnavailable
en het verzoek opnieuw te berechten als het zich voordoet. Ik gebruik ook een Decorrelated Jitter Backoff
strategie om te wachten tussen retrieves. Dit is een goede strategie om te gebruiken omdat het helpt om te voorkomen dat de 'donderende kudde' probleem waar alle klanten opnieuw proberen op hetzelfde moment (ook al is het alleen ik:)). Dit kan helpen om de belasting op de server te verminderen en de kans op succes van het verzoek te vergroten.
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);
}
Gebruik makend van een retry-beleid voor HttpClient
verzoeken is een belangrijke manier om de betrouwbaarheid te verbeteren. Terwijl we graag denken dat onze web services altijd beschikbaar zijn is er altijd SOME downtime (in mijn geval wanneer bijvoorbeeld Watchtower Detecteert een update is in afwachting en herstart de Umami container). Dus het hebben van een retry beleid op zijn plaats kan helpen om ervoor te zorgen dat uw toepassing kan omgaan met deze situaties sierlijk.
Een ander gebruik dat ik van Polly maak is bij het laden en opslaan van bestanden in mijn applicatie. Ik gebruik een FileSystemWatcher
om de map waar mijn markdown bestanden worden opgeslagen te controleren. Wanneer een bestand is aangemaakt of bijgewerkt, laad ik het bestand en verwerk het. Dit kan een probleem zijn als het bestand nog steeds wordt geschreven wanneer de gebeurtenis wordt geactiveerd. Dus ik gebruik een RetryPolicy
Om deze situatie aan te pakken.
Hier kan je zien dat ik de IOException
die wordt gegooid wanneer het bestand in gebruik is en de bewerking opnieuw proberen. Ik gebruik een WaitAndRetryAsync
beleid om de operatie opnieuw te proberen 5 keer met een vertraging tussen elke retry. Dit stelt me in staat om de situatie te behandelen waar het bestand nog steeds wordt geschreven en opnieuw proberen van de operatie totdat het slaagt.
Wat belangrijk is, is dat ik 'opgeef'. IOException
van mijn SavePost
methode die het Polly beleid in staat stelt om de retry te verwerken. Dit is een goed patroon te volgen als het kunt u omgaan met de retry logica op een centrale plaats en geen zorgen te maken over het in elke methode die nodig zou kunnen zijn om een operatie opnieuw te proberen.
In het algemeen altijd omgaan met uitzonderingen waar u kunt en overgeven naar een hoger niveau waar je ze op een meer gecentraliseerde manier kunt hanteren (of loggen). Dit kan helpen om de complexiteit van uw code te verminderen en het gemakkelijker te maken om op een consistente manier met uitzonderingen om te gaan.
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);
...
});
...
}
Nogmaals dit is een voorbeeld van mijn code interactie met een externe dienst, in dit geval het bestandssysteem. Waar ik bepaalde fouttypen te verwachten. Ik log deze ook met behulp van SerilogTracing Die stuurt ze naar Seq die THAN stuurt me een e-mail wanneer de foutmelding is ingelogd, zodat ik kan identificeren alle problemen die zich kunnen voordoen.
Nogmaals, de algemene aanpak is om uitzonderingen aan te pakken waar je kunt, ze in te loggen wanneer je dat niet kunt en ervoor te zorgen dat je een manier hebt om te weten wat er gebeurt. Dit kan helpen om ervoor te zorgen dat uw toepassing is veerkrachtig en kan omgaan met alle problemen die zich kunnen voordoen.
In mijn Email Service gebruik ik zowel de CircuitBreaker
patroon en een retry policy. De retry policy wordt gebruikt om de zaak te behandelen waar de e-mail service niet beschikbaar is en de stroomonderbreker wordt gebruikt om de zaak te behandelen waar de e-mail service is bezet of overbelast.
Beide zijn belangrijk in het geval van e-mails; SMTP is een relatief langzaam en potentieel onbetrouwbaar protocol.
Hier behandel ik SmtpExceptions, waar wanneer een fout afkomstig is van de SMTP service het eerst drie keer opnieuw zal proberen met een vertraging tussen elke retry. Als de service nog steeds niet beschikbaar is na de retrieves (en nog twee voor een nieuwe verzending), zal de stroomonderbreker openen en stoppen met het versturen van e-mails voor een minuut. Dit kan helpen om te voorkomen dat de e-mailservice wordt overbelast (en mijn account wordt geblokkeerd) en het verbeteren van de kans dat de e-mail succesvol wordt verzonden.
// 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);
Dit wordt dan gebruikt in mijn E-mail Sending lus die wacht op nieuwe berichten worden toegevoegd aan het kanaal vervolgens probeert om ze te verzenden.
Dit maakt gebruik van alle functionaliteit in het verpakte beleid om veerkracht toe te voegen aan het e-mailverzendproces.
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 is een krachtige bibliotheek die u kan helpen om veerkracht toe te voegen aan uw toepassingen. Door Polly te gebruiken kunt u retries, stroomonderbrekers, time-outs, snelheidsbegrenzers, terugvallers en afdekkingen in uw toepassing verwerken. Dit kan helpen om ervoor te zorgen dat uw toepassing is betrouwbaar en kan omgaan met alle problemen die zich kunnen voordoen. In dit bericht heb ik echt een aspect van Polly behandeld; retries, dit is een mechanisme dat de veerkracht en betrouwbaarheid van uw toepassing kan verbeteren. Door Polly te gebruiken kunt u retries op een consistente manier behandelen en ervoor zorgen dat uw toepassing alle problemen die zich kunnen voordoen kan behandelen.