सेवानिवृत्ति के लिए पोली का उपयोग करना
परिचय
पोलीCity name (optional, probably does not need a translation) किसी भी .NET विकासकर्ता के एक महत्वपूर्ण हिस्सा है। मैं इस अनुप्रयोग में रिट्री को संभालने के लिए पॉली का उपयोग करें.
पोलीCity name (optional, probably does not need a translation)
While Polly does retries really well it's not all it can do
इन से लिया गया है पॉली का मुख्य पृष्ठ और मुख्य नमूने हैं जो आप Polly के साथ उपयोग कर सकते हैं
- पुनः प्रयास करें: यदि कुछ असफल होता है तो फिर से कोशिश करें
- सर्किट ब्रेकर
- समय समाप्ति: यदि कुछ अधिक समय लग जाता है तो छोड़ें। यह खाली स्थान और संसाधनों को मुक्त करके आपके प्रदर्शन में सुधार कर सकता है।
- दर सीमाकर्ता: आप कितना अनुरोध कर रहे हैं या स्वीकार करते हैं को सीमित करें।
- फेलबैक Hedging: एक ही समय में एक से अधिक काम करें और सबसे तेजी से एक लेने के लिए
मैं पॉली का प्रयोग कैसे करता हूँ
इस अनुप्रयोग में मैं पॉली को कई स्थानों पर प्रयोग करता हूँ
पृष्ठभूमि अनुवाद सेवा
मेरे अनुवाद सेवा आरंभ करने के लिए और EasyNMT सर्वर की जाँच के लिए उपलब्ध हैं मेरे संपादक 'toy' आपको मार्कडाउन और मेरे लिए ' उड़ान पर ' अनुवाद करने के लिए सक्षम करें ब्लॉग पोस्ट अनुवाद इंजनतो यह महत्वपूर्ण है मैं EasyNMT की जाँच करता हूँ कि यह नीचे नहीं गया है
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;
}
}
यहाँ आप देख सकते हैं कि हम एक Polly पुनः प्रयास नीति सेटअप कर रहे है जो प्रत्येक पुनः प्रयास के बीच 3 बार फिर से कोशिश करेगा और एक \5-सेकेंड प्रतीक्षा के साथ. यदि सेवा पुनः प्रयासों के बाद अभी भी उपलब्ध नहीं है तो हम एक त्रुटि लॉग करें और विफलता को सेट करके संभालने TranslationServiceUp गलत को फ्लैग करें. यह तब किसी भी अनुवाद सेवा का उपयोग करने वाले सेवाओं को यह पता लगाने के लिए अनुमति देता है कि वह उपलब्ध नहीं है
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
मैं अपनी उमामी API को अनुरोध करने के दौरान पुनः प्रयासों को संभालने के लिए मेरी नेट लाइब्रेरी में पॉली का भी उपयोग करता हूँ
यहाँ मैं अपने सेटअप HttpClient एक पुनः प्रयास नीति का उपयोग करने के लिए HttpStatusCode.ServiceUnavailable और यदि यह होता है तो अनुरोध पुनः प्रयास करना. I'm भी एक का उपयोग कर Decorrelated Jitter Backoff पुनः प्रयासों के बीच प्रतीक्षा करने की रणनीति. यह उपयोग में एक अच्छा रणनीति है क्योंकि यह सभी क्लाइंटों को एक ही समय पर पुनः प्रयास करने की समस्या से बचने में मदद करता है 'thundering herd
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 अनुरोध विश्वसनीयता में सुधार का एक महत्वपूर्ण तरीका है वॉचटोवर पता लगाता है कि अद्यतन लंबित है और Umami कन्टेनर को फिर से आरंभ करता है
फ़ाइल सिस्टम वॉकर
एक अन्य उपयोग मैं Polly का करता है जब मेरे अनुप्रयोग में फ़ाइलों को लोड करने और सहेजने के साथ काम करते हैं FileSystemWatcher डिरेक्ट्री पर मॉनीटर करने के लिए जहाँ मेरी मार्क डाउन फ़ाइलें भंडारित हैं. जब कोई फ़ाइल बनाया जाता है या अद्यतन किया गया है मैं फ़ाइल को लोड करता हूँ और इसे संसाधित करता है RetryPolicy इस स्थिति को संभालने के लिए
यहाँ आप देख सकते हैं मैं संभाल सकता है IOException जो फ़ाइल उपयोग में है जब फेंक दिया जाता है और फिर से ऑपरेशन चलाएँ. मैं एक का प्रयोग करता हूँ WaitAndRetryAsync कार्य को पुनः प्रयास करने की नीति 5 बार प्रत्येक पुनः प्रयास के बीच विलंब के साथ-साथ
यह महत्वपूर्ण है कि मैं 'up' को फेंक IOException से SavePost विधि जो पॉली नीति को पुनः प्रयास को संभालने के लिए अनुमति देता है
सामान्यतः हमेशा अपवादों को संभालें जहाँ आप कर सकते हैं और उखाड़ना एक उच्चतर स्तर पर जहाँ आप उन्हें अधिक केंद्रित तरीके से संभाल सकते हैं (या उन्हें लॉग करें). यह आपके कोड की जटिलता को कम करने में मदद कर सकता है और एक सुसंगत तरीके से अपवादों को संभालना आसान बना देता है
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);
...
});
...
}
फिर यह मेरे कोड का एक उदाहरण है जो बाहरी सेवा के साथ आदान-प्रदान करता है। सेरिलॉग ट्रैसिंग जो उन्हें Seq को भेजता है जो फिर मुझे एक ईमेल भेज देता है जब errror लॉग किया जाता है ताकि मैं कोई भी समस्याओं की पहचान कर सकते हैं जो हो सकता है हो रही है
पुनः, सामान्य दृष्टिकोण अपवादों को संभालने के लिए है जहाँ आप कर सकते हैं, जहां आप उन्हें लॉग कर सकते है जब आप कर सकता है, और यह सुनिश्चित करने का एक तरीका है कि आपको पता है क्या हो रहा है।
ईमेल सेवा
मेरे ईमेल सेवा में मैं दोनों का उपयोग करता हूँ CircuitBreaker पैटर्न और पुनः प्रयास नीति. पुनः प्रयास पॉलिसी का प्रयोग उस मामले को संभालने के लिए किया जाता है जहां ईमेल सेवा उपलब्ध नहीं है और सर्किट ब्रेकर का उपयोग उस मामले की संभाल करने के लिए होता है जहाँ ईमेल सेवा व्यस्त या अतिभारित है
एसएमटीपी अपेक्षाकृत धीमी और संभावित रूप से अविश्वसनीय प्रोटोकॉल है
यहाँ मैं SMtp अपवादों को संभालता हूँ, जहां जब एक त्रुटि एसएमटीपी सेवा से आती है तो यह पहले तीन बार पुनः प्रयास करेगा और प्रत्येक पुनः प्रयास के बीच विलंब होगा।
// 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);
यह तब मेरे ईमेल प्रेषण लूप में उपयोग किया जाता है जो चैनल के लिए नए संदेश जोड़ने की प्रतीक्षा करता है फिर उन्हें भेजने का प्रयास करता है
यह ई-मेल भेजने की प्रक्रिया में लपेटी गई नीति के सभी functioanlity का उपयोग करता है
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 के एक पहलू को शामिल किया है।