نمط قاطع الدائرة

Azure

عالج الأخطاء التي قد تستغرق مدد متغيرة لإصلاحها عند الاتصال بخدمة أو مورد عن بُعد. يمكن لقاطع الدائرة أن يحسن استقرار ومرونة التطبيق.

السياق والمشكلة

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

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

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

حل

يقول مايكل نيجارد في كتابه Release It! أن نمط قاطع الدائرة يمكن منع محاولة تنفيذ عملية من المحتمل تكرار فشلها. السماح له بالاستمرار دون انتظار إصلاح الخطأ أو إضاعة CPU بينما يحدد أن الخطأ طويل الأمد. كما يستطيع نمط قاطع الدائرة اكتشاف ما إذا كان قد تم حل الخطأ أم لا. عند إصلاح المشكلة، يمكن للتطبيق محاولة استدعاء العملية.

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

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

يمكن تنفيذ الوكيل كآلة حالة مع الحالات التالية التي تحاكي وظيفة قاطع الدوائر الكهربائية:

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

    الغرض من مؤقت المهلة هو منح النظام الوقت لإصلاح المشكلة التي تسببت في الفشل قبل السماح للتطبيق بمحاولة تنفيذ العملية مرة أخرى.

  • فتح: يحدث فشل فوري للطلب من التطبيق ويتم إرجاع استثناء إلى التطبيق.

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

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

حالات قاطع الدائرة

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

ربما تحدث معالجة استرداد النظام خارجيا عن طريق استعادة مكون فاشل أو إعادة تشغيله أو إصلاح شبكة اتصال.

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

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

المسائل والاعتبارات

يجب مراعاة النقاط التالية عند تحديد كيفية تنفيذ هذا النمط:

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

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

التسجيل. يجب أن يسجل قاطع الدائرة جميع الطلبات الفاشلة (وربما الطلبات الناجحة) لتمكين المسؤول من مراقبة صحة العملية.

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

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

تجاوز يدوي. في نظام يكون فيه وقت الاسترداد لعملية فاشلة متغيرا للغاية، من المفيد توفير خيار إعادة تعيين يدوي يمكن المسؤول من إغلاق قاطع دائرة (وإعادة تعيين عداد الفشل). وبالمثل، يمكن للمسؤول فرض قاطع دائرة إلى حالة فتح (وإعادة تشغيل مؤقت المهلة) إذا كانت العملية المحمية بواسطة قاطع الدائرة غير متوفرة مؤقتا.

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

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

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

إشعار

يمكن للخدمة إرجاع HTTP 429 (طلبات زائدة عن الحد) إذا كانت تقوم بتقييد العميل، أو HTTP 503 (الخدمة غير متوفرة) إذا لم تكن الخدمة متوفرة حاليا. ويمكن أن تتضمن الاستجابة معلومات إضافية، مثل مدة التأخير المتوقعة.

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

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

موعد استخدام النمط

استخدم هذا النمط:

  • لمنع تطبيق من محاولة استدعاء خدمة بعيدة أو الوصول إلى مورد مشترك إذا تيقن فشل هذه العملية.

لا يوصى بهذا النمط عند:

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

تصميم حمل العمل

يجب على المهندس المعماري تقييم كيفية استخدام نمط قاطع الدوائر في تصميم حمل العمل الخاص بهم لمعالجة الأهداف والمبادئ التي تغطيها ركائز Azure Well-Architected Framework. على سبيل المثال:

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

- RE:03 تحليل وضع الفشل
- RE:07 أخطاء عابرة
- RE:07 الحفاظ على الذات
تساعد كفاءة الأداء حمل العمل الخاص بك على تلبية الطلبات بكفاءة من خلال التحسينات في التحجيم والبيانات والرمز. يتجنب هذا النمط نهج إعادة المحاولة عند الخطأ الذي يمكن أن يؤدي إلى استخدام الموارد بشكل مفرط أثناء استرداد التبعية ويمكنه أيضا التحميل الزائد للأداء على تبعية تحاول الاسترداد.

- PE:07 Code والبنية الأساسية
- PE:11 Live-issues responses

كما هو الحال مع أي قرار تصميم، ضع في اعتبارك أي مفاضلات ضد أهداف الركائز الأخرى التي يمكن إدخالها مع هذا النمط.

مثال

في تطبيق ويب، يتم ملء العديد من الصفحات بالبيانات التي تم استردادها من خدمة خارجية. إذا استنفذ النظام الحد الأدنى من التخزين المؤقت، فإن معظم مرات الوصول إلى هذه الصفحات ستتسبب في قيام الخدمة بجولة ذهابًا وإيابًا. يمكن تكوين الاتصالات من تطبيق الويب إلى الخدمة مع فترة مهلة (عادة 60 ثانية)، وإذا لم تستجب الخدمة في هذه المرة، فسيفترض المنطق في كل صفحة ويب أن الخدمة غير متوفرة ومن ثم يطرح استثناء.

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

قد يؤدي تغيير حجم النظام عن طريق إضافة المزيد من خوادم الويب وتنفيذ موازنة التحميل إلى تأخير عند استنفاد الموارد، ولكنه لن يحل المشكلة لأن طلبات المستخدم ستظل غير مستجيبة وقد تستنفذ جميع خوادم الويب مواردها في النهاية.

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

تحتفظ الفئة CircuitBreaker بمعلومات الحالة حول قاطع دائرة في كائن ينفذ الواجهة ICircuitBreakerStateStore الموضحة في التعليمات البرمجية التالية.

interface ICircuitBreakerStateStore
{
  CircuitBreakerStateEnum State { get; }

  Exception LastException { get; }

  DateTime LastStateChangedDateUtc { get; }

  void Trip(Exception ex);

  void Reset();

  void HalfOpen();

  bool IsClosed { get; }
}

تشير الخاصية State إلى الحالة الحالية لقاطع الدائرة، وستكون إما مفتوحة أو مفتوحة جزئيًا أو مغلقة كما هو محدد بواسطة CircuitBreakerStateEnumقائمة التعداد. يجب أن تكون الخاصية IsClosed صحيحة إذا كان قاطع الدائرة مغلقا، وتكون خطأ إذا كان مفتوحا أو مفتوحة جزئيًا. يقوم الأسلوب Trip بتبديل حالة قاطع الدائرة إلى الحالة المفتوحة ويسجل الاستثناء الذي تسبب في تغيير الحالة، بالإضافة لتسجيل تاريخ ووقت حدوث الاستثناء. ترجع الخاصيتين LastException و LastStateChangedDateUtc هذه المعلومات. الأسلوب Reset يغلق قاطع الدائرة، ويعين الأسلوب HalfOpen قاطع الدائرة إلى مفتوح جزئيًا.

تحتوي الفئة InMemoryCircuitBreakerStateStore في المثال على تنفيذ الواجهة ICircuitBreakerStateStore. تنشئ الفئة CircuitBreaker مثيلا لهذه الفئة للاحتفاظ بحالة قاطع الدائرة.

يقوم الأسلوب ExecuteAction في الفئة CircuitBreaker بتضمين عملية، محددة كمفوض Action. إذا كان قاطع الدائرة مغلقا، يستدعي ExecuteAction المفوض Action. إذا فشلت العملية، يستدعي معالج الاستثناء TrackException، الذي يعين حالة قاطع الدائرة إلة مفتوح. يوضح مثال التعليمات البرمجية التالي هذا التدفق.

public class CircuitBreaker
{
  private readonly ICircuitBreakerStateStore stateStore =
    CircuitBreakerStateStoreFactory.GetCircuitBreakerStateStore();

  private readonly object halfOpenSyncObject = new object ();
  ...
  public bool IsClosed { get { return stateStore.IsClosed; } }

  public bool IsOpen { get { return !IsClosed; } }

  public void ExecuteAction(Action action)
  {
    ...
    if (IsOpen)
    {
      // The circuit breaker is Open.
      ... (see code sample below for details)
    }

    // The circuit breaker is Closed, execute the action.
    try
    {
      action();
    }
    catch (Exception ex)
    {
      // If an exception still occurs here, simply
      // retrip the breaker immediately.
      this.TrackException(ex);

      // Throw the exception so that the caller can tell
      // the type of exception that was thrown.
      throw;
    }
  }

  private void TrackException(Exception ex)
  {
    // For simplicity in this example, open the circuit breaker on the first exception.
    // In reality this would be more complex. A certain type of exception, such as one
    // that indicates a service is offline, might trip the circuit breaker immediately.
    // Alternatively it might count exceptions locally or across multiple instances and
    // use this value over time, or the exception/success ratio based on the exception
    // types, to open the circuit breaker.
    this.stateStore.Trip(ex);
  }
}

يوضح المثال التالي التعليمات البرمجية (محذفة من المثال السابق) التي يتم تنفيذها إذا لم يتم إغلاق قاطع الدائرة. يتحقق أولا مما إذا كان قاطع الدائرة مفتوحا لفترة أطول من الوقت المحدد له بواسطة الحقل المحلي OpenToHalfOpenWaitTime في الفئة CircuitBreaker. إذا كانت هذه هي الحالة، يقوم الأسلوب ExecuteAction بتعيين قاطع الدائرة إلى مفتوح جزئيًا، ثم يحاول تنفيذ العملية المحددة بواسطة المفوض Action.

إذا نجحت العملية، تتم إعادة تعيين قاطع الدائرة إلى الحالة المغلقة. إذا فشلت العملية، تعود مرة أخرى إلى الحالة المفتوحة ويُحدث وقت صدور الاستثناء بحيث ينتظر قاطع الدائرة لفترة أخرى قبل إعادة المحاولة مرة أخرى.

إذا كان قاطع الدائرة مفتوحا لفترة قصيرة فقط، أقل من القيمة OpenToHalfOpenWaitTime، فإن الأسلوب ExecuteAction يطرح ببساطة الاستثناء CircuitBreakerOpenException ويرجع الخطأ الذي تسبب في انتقال قاطع الدائرة إلى الحالة المفتوحة.

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

    ...
    if (IsOpen)
    {
      // The circuit breaker is Open. Check if the Open timeout has expired.
      // If it has, set the state to HalfOpen. Another approach might be to
      // check for the HalfOpen state that had be set by some other operation.
      if (stateStore.LastStateChangedDateUtc + OpenToHalfOpenWaitTime < DateTime.UtcNow)
      {
        // The Open timeout has expired. Allow one operation to execute. Note that, in
        // this example, the circuit breaker is set to HalfOpen after being
        // in the Open state for some period of time. An alternative would be to set
        // this using some other approach such as a timer, test method, manually, and
        // so on, and check the state here to determine how to handle execution
        // of the action.
        // Limit the number of threads to be executed when the breaker is HalfOpen.
        // An alternative would be to use a more complex approach to determine which
        // threads or how many are allowed to execute, or to execute a simple test
        // method instead.
        bool lockTaken = false;
        try
        {
          Monitor.TryEnter(halfOpenSyncObject, ref lockTaken);
          if (lockTaken)
          {
            // Set the circuit breaker state to HalfOpen.
            stateStore.HalfOpen();

            // Attempt the operation.
            action();

            // If this action succeeds, reset the state and allow other operations.
            // In reality, instead of immediately returning to the Closed state, a counter
            // here would record the number of successful operations and return the
            // circuit breaker to the Closed state only after a specified number succeed.
            this.stateStore.Reset();
            return;
          }
        }
        catch (Exception ex)
        {
          // If there's still an exception, trip the breaker again immediately.
          this.stateStore.Trip(ex);

          // Throw the exception so that the caller knows which exception occurred.
          throw;
        }
        finally
        {
          if (lockTaken)
          {
            Monitor.Exit(halfOpenSyncObject);
          }
        }
      }
      // The Open timeout hasn't yet expired. Throw a CircuitBreakerOpen exception to
      // inform the caller that the call was not actually attempted,
      // and return the most recent exception received.
      throw new CircuitBreakerOpenException(stateStore.LastException);
    }
    ...

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

var breaker = new CircuitBreaker();

try
{
  breaker.ExecuteAction(() =>
  {
    // Operation protected by the circuit breaker.
    ...
  });
}
catch (CircuitBreakerOpenException ex)
{
  // Perform some different action when the breaker is open.
  // Last exception details are in the inner exception.
  ...
}
catch (Exception ex)
{
  ...
}

قد تكون الأنماط التالية مفيدة أيضاً عند تنفيذ هذا النمط:

  • يوضح لك نمط تطبيق الويب الموثوق به كيفية تطبيق نمط قاطع الدائرة على تطبيقات الويب المتقاربة على السحابة.

  • نمط إعادة المحاولة. صّف كيفية معالجة تطبيق لحالات التعطل المتوقعة والمؤقتة عند محاولة الاتصال بمورد شبكة أو خدمة عن طريق إعادة محاولة إجراء عملية فشلت مسبقًا بشفافية.

  • مراقبة نقطة النهاية الصحيحة. قد يتمكن مجزئ الدائرة من اختبار صحة الخدمة عن طريق إرسال طلب إلى نقطة نهاية تعرضها الخدمة. يجب أن ترجع الخدمة معلومات تشير إلى حالتها.