Back to "استخدام لمتكث"

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

استخدام لمتكث

Sunday, 15 September 2024

أولاً

بولي بولي هو جزء حاسم من أي مجموعة أدوات لمطوري الشبكة. المكتبة هي التي تسمح لك بتحديد سياسات التعامل مع الاستثناءات والتراجعات في طلبك. في هذه المادة، سوف نستكشف كيفية: (أ) مـا مـن مـن مـن مـن مـن مـن مـن مـن مـن مـن استخدم بولي للتعامل مع الريتريات في هذا التطبيق.

بولي بولي

في حين أن (بولي) تقوم بالتمريرات بشكل جيد ليس كل ما تستطيع القيام به، إنها في الواقع مجموعة أدوات لإضافة المرونة إلى تطبيقاتك. على حد سواء إجراء المكالمات إلى الخدمات الخارجية وداخليا.

هذه مأخوذة من الصفحة الرئيسية والأنماط الرئيسية التي يمكنك استخدامها مع بولي:

  • حاول مرة أخرى إذا فشل شيء ما. ويمكن أن يكون ذلك مفيدا عندما تكون المشكلة مؤقتة وقد تزول.
  • توقف عن المحاولة إذا كان هناك شيء مكسور أو مشغول. وهذا يمكن ان يفيدك بتفادي اضاعة الوقت وجعل الامور اسوأ. ويمكنها أيضا أن تدعم نظام الاسترداد.
  • أستسلمي إن استغرق الأمر وقتاً طويلاً وهذا يمكن أن يحسن أداءكم بتحرير الفضاء والموارد.
  • الحد الأدنى: حدّد عدد الطلبات التي تطلبها أو تقبلها. هذا من شأنه أن يمكّنكم من التحكم في الحمل ومنع المشاكل أو العقوبات.
  • افعل شيئاً آخر إذا فشل شيء ما. هذا من شأنه أن يحسن من خبرة المستخدم ويبقي البرنامج يعمل. التحوط: القيام بأكثر من شيء واحد في نفس الوقت واتخاذ أسرع شيء. هذا يمكن أن يجعل برنامجك أسرع وأكثر استجابة.

كيف أستعمل بولي

في هذا التطبيق أستخدم بولي في أماكن متعددة.

خلفية

لبداية خدماتي للترجمة والتحقق من خوادم (ايزي نات) متاحة. يسمح لي 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 أعلام أن تكون مُنْزِلَة. ويتيح ذلك لأي خدمات تستخدم دائرة الترجمة التحريرية أن تعرف أنها غير متاحة.

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

الشبكة الوطنية (Net)

أنا أيضاً أستخدم بولي في مكتبة إمامي. نت للتعامل مع 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 التي ترسل لي البريد الإلكتروني عندما يتم تسجيل الخطأ حتى أتمكن من تحديد أي قضايا قد تحدث.

مرة أخرى، النهج العام هو التعامل مع الاستثناءات حيث يمكنك، تسجيلها عندما لا تستطيع وضمان أن لديك طريقة لمعرفة ما يحدث. ويمكن ان يساعد ذلك على ضمان مرونة طلبك وتعامله مع اي مسائل قد تنشأ.

& & & دعمSSSSS

في خدمة بريدي الإلكتروني أستخدم كلاً من 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);
            }
        }

في الإستنتاج

بولي هي مكتبة قوية التي يمكن أن تساعدك على إضافة المرونة إلى تطبيقاتك. باستخدام بولي، يمكنك التعامل مع القصبات، ومفرقات الدوائر، والفترات الزمنية، والحد من المعدلات، والتراجع، والتحوط في تطبيقك. من شأن ذلك أن يساعد على ضمان أن يكون طلبك موثوقا به وأن يعالج أي مسائل قد تنشأ. في هذا المقال قمت حقاً بتغطية جانب واحد من بولي؛ إعادة صياغة، هذه آلية التي يمكن أن تحسن مرونة وموثوقية تطبيقك. باستخدام بولي يمكنك التعامل مع القصبات بطريقة متسقة والتأكد من أن تطبيقك يمكن أن يعالج أي مشاكل قد تحدث.

logo

©2024 Scott Galloway