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
بولي بولي هو جزء حاسم من أي مجموعة أدوات لمطوري الشبكة. المكتبة هي التي تسمح لك بتحديد سياسات التعامل مع الاستثناءات والتراجعات في طلبك. في هذه المادة، سوف نستكشف كيفية: (أ) مـا مـن مـن مـن مـن مـن مـن مـن مـن مـن مـن استخدم بولي للتعامل مع الريتريات في هذا التطبيق.
في حين أن (بولي) تقوم بالتمريرات بشكل جيد ليس كل ما تستطيع القيام به، إنها في الواقع مجموعة أدوات لإضافة المرونة إلى تطبيقاتك. على حد سواء إجراء المكالمات إلى الخدمات الخارجية وداخليا.
هذه مأخوذة من الصفحة الرئيسية والأنماط الرئيسية التي يمكنك استخدامها مع بولي:
في هذا التطبيق أستخدم بولي في أماكن متعددة.
لبداية خدماتي للترجمة والتحقق من خوادم (ايزي نات) متاحة. يسمح لي Thsi للتحقق من الخدمة متاحة قبل البدء في 'عرض' خدمة الترجمة في تطبيقي. ستتذكر أن كلا هذا يستخدم لـ تحريري 'Toy' لتمكينكم من أن تترجموا هدفكم إلى أسفل و من أجل بلدي 'على ذبابة' محرّك المترجم المترجم/ / / / لذا فمن المهم أن أتاكد من أن (ايزي نات) لم يهبط (ويتمكّن من الانتظار حتى يصل، والذي يمكن أن يستغرق بضع ثوان).
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
أعلام أن تكون مُنْزِلَة. ويتيح ذلك لأي خدمات تستخدم دائرة الترجمة التحريرية أن تعرف أنها غير متاحة.
أنا أيضاً أستخدم بولي في مكتبة إمامي. نت للتعامل مع Retrees عند تقديم الطلبات إلى Amamami API. وهذا جزء حاسم من المكتبة حيث أنه يسمح لي بمعالجة أي مسائل مع API وإعادة صياغة الطلب إذا لزم الأمر.
هنا قمت بتأسيس HttpClient
في هذه الحالة أنا أفحص لـ a HttpStatusCode.ServiceUnavailable
(أ) إعادة صياغة الطلب في حالة حدوثه. أنا أيضاً استخدم Decorrelated Jitter Backoff
الاستراتيجية للانتظار بين الترميزات. هذه استراتيجية جيدة لاستخدامها كما أنها تساعد على تجنب مشكلة "التأثير القطيع" حيث أن جميع العملاء يعيدون المحاولة في نفس الوقت (بالرغم من أنني فقط:)). وهذا يمكن أن يساعد على تقليل الحمل على الخادم وتحسين فرص نجاح الطلب.
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
(أ) أن تكون الطلبات طريقة هامة لتحسين الموثوقية. بينما نحب أن نعتقد أن خدماتنا على شبكة الويب متاحة دائماً دائماً هناك دائماً بعض أوقات التوقف (في حالتي عندما على سبيل المثال ( ١ كورنثوس ٧ : ٧ ) فَقَدْ تَعَلَّمْتُ مِنْهُمْ أَنْ يَسْتَطِيعُوا أَنْ يَعْرِفُوا عَلَيْهِمْ أَنْ يَتَعَلَّمُوا عَلَيْهِمْ أَنْ يَتَعَلَّمُوا عَلَيْهِمْ أَنْ يَتَعَلَّمُوا عَلَيْهِمْ. يُكشف عن تحديث معلق ويُعيد تشغيل حاوية أمّامي). وهكذا ، يمكن ان يساعد وضع سياسة لإعادة الاختبار على ضمان قدرة طلبك على التعامل مع هذه الحالات برشاقة.
استخدام آخر أقوم به لبولي هو عند التعامل مع ملفات التحميل والادخار في تطبيقي. أنا استخدم FileSystemWatcher
لمراقبة الدليل حيث يتم تخزين ملفاتي عندما يتم إنشاء ملف أو تحديثه، أقوم بتحميل الملف وتجهيزه. هذه يمكن أن تكون مشكلة إذا كان الملف لا يزال مكتوباً إلى متى حدث. اذاً انا استخدم RetryPolicy
للتعامل مع هذا الوضع
هنا يمكنك أن ترى أنا التعامل مع IOException
يتم إلقاؤها عندما يكون الملف مستخدماً و إعادة توجيه العملية. أنا استخدم WaitAndRetryAsync
إعادة تجربة العملية 5 مرات مع تأخير بين كل إعادة. هذا يسمح لي بالتعامل مع الوضع حيث الملف لا يزال مكتوباً وإعادة كتابة العملية إلى أن تنجح.
ما هو المهم هنا هو أنني أتقيأ 'علي' إلى 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);
...
});
...
}
مرة أخرى هذا مثال على تفاعل شفرتي مع خدمة خارجية، في هذه الحالة نظام الملفات. حيث اتوقع وجود أنواع معينة من الأخطاء. هذا ايضاً SERILTS التي ترسلها إلى Seq التي ترسل لي البريد الإلكتروني عندما يتم تسجيل الخطأ حتى أتمكن من تحديد أي قضايا قد تحدث.
مرة أخرى، النهج العام هو التعامل مع الاستثناءات حيث يمكنك، تسجيلها عندما لا تستطيع وضمان أن لديك طريقة لمعرفة ما يحدث. ويمكن ان يساعد ذلك على ضمان مرونة طلبك وتعامله مع اي مسائل قد تنشأ.
في خدمة بريدي الإلكتروني أستخدم كلاً من CircuitBreaker
وسياسة إعادة صياغة. تُستخدم سياسة إعادة التسجيل للتعامل مع الحالة التي لا تكون فيها خدمة البريد الإلكتروني متاحة ويُستخدم مفكك الدائرة للتعامل مع الحالة التي تكون فيها خدمة البريد الإلكتروني مشغولة أو مُثقلة.
وكلا الأمرين مهم في حالة البريد الإلكتروني؛ أما SMTP فهو بروتوكول بطيء نسبياً ويحتمل أن يكون غير موثوق به.
هنا أتعامل مع Smtpexcoptions، حيث عندما يأتي خطأ من خدمة 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);
هذا هو مُستخدَم بوصة بريدي الإلكتروني إرسال حلقة إلى جديد رسائل إلى القناة ثمّ إلى إرسال.
هذا يستخدم كل الفكتيرية في السياسة الملفوفة لإضافة المرونة إلى عملية إرسال البريد الإلكتروني.
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);
}
}
بولي هي مكتبة قوية التي يمكن أن تساعدك على إضافة المرونة إلى تطبيقاتك. باستخدام بولي، يمكنك التعامل مع القصبات، ومفرقات الدوائر، والفترات الزمنية، والحد من المعدلات، والتراجع، والتحوط في تطبيقك. من شأن ذلك أن يساعد على ضمان أن يكون طلبك موثوقا به وأن يعالج أي مسائل قد تنشأ. في هذا المقال قمت حقاً بتغطية جانب واحد من بولي؛ إعادة صياغة، هذه آلية التي يمكن أن تحسن مرونة وموثوقية تطبيقك. باستخدام بولي يمكنك التعامل مع القصبات بطريقة متسقة والتأكد من أن تطبيقك يمكن أن يعالج أي مشاكل قد تحدث.