كان عطلٌ واحدٌ يُسقط النظام بأكمله: كيف أنقذنا ‘نمط قاطع الدائرة’ من جحيم الانهيارات المتسلسلة؟

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

كنا وقتها شغالين على نظام ضخم للتجارة الإلكترونية، مبني على معمارية الخدمات المصغرة (Microservices). كل شيء كان ماشي زي الحلاوة، والنظام شغال زي الساعة. ليلة خميس، قبل إطلاق حملة تخفيضات كبيرة بيوم واحد، كنا قاعدين في المكتب بنراقب الأنظمة وبنجهز الأمور. الأجواء كانت هادية، والكل متفائل. وفجأة، بدون سابق إنذار، بدأت التنبيهات (Alerts) تنهال علينا زي المطر. الموقع بطيء… بطيء جداً… ثم توقف تماماً. “Internal Server Error” في كل مكان.

الدنيا قامت وقعدت، والفريق كله صار يركض زي المجانين. شو اللي صار؟ بعد ساعات من الحفر في سجلات الأخطاء (Logs)، اكتشفنا المصيبة. خدمة صغيرة، شبه تافهة، مسؤولة عن إظهار “اقتراحات الأصدقاء” للمستخدم، دخلت في حلقة لا نهائية من الأخطاء بسبب استعلام خاطئ لقاعدة البيانات. المشكلة إن كل طلب لصفحتنا الرئيسية كان يستدعي هذه الخدمة. ولما الخدمة هاي صارت تبطّئ وتُرجع أخطاء، كل طلب جديد صار ينتظرها… وينتظر… وينتظر… حتى استنفذنا كل الـ “threads” المتاحة في خوادم الويب الرئيسية. النظام كله انخنق ومات. عطل في خدمة غير أساسية بالمرة، أسقط النظام بأكمله. وقتها، عرفنا إنه لازم نلاقي حل جذري، حل يمنع هذا “التأثير الدومينو” أو ما يسمى بـ “الانهيار المتسلسل” (Cascading Failure). وهنا كانت بداية رحلتنا مع بطل قصتنا: نمط قاطع الدائرة.

ما هو جحيم الانهيارات المتسلسلة (Cascading Failures)؟

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

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

  1. خدمة “اقتراحات الأصدقاء” (Service A) فشلت.
  2. الخدمة الرئيسية (Service B) التي تستدعي Service A أصبحت بطيئة جداً لأنها تنتظر ردًا لن يأتي أبدًا.
  3. كل طلب جديد لـ Service B يستهلك موارد (threads, memory) في الانتظار.
  4. بعد فترة قصيرة، استُنفدت كل موارد Service B، وأصبحت غير قادرة على خدمة أي طلب، حتى الطلبات التي لا علاقة لها بـ Service A.
  5. النتيجة: النظام بأكمله يتوقف عن العمل بسبب عطل صغير في جزء غير حيوي منه.

“محاولة إعادة الطلب (Retry) بشكل أعمى على خدمة فاشلة لا تحل المشكلة، بل تزيد الطين بلة. أنت كمن يصب الزيت على النار، فتزيد الضغط على خدمة هي أصلاً تحتضر.”

البطل المنقذ: نمط قاطع الدائرة (The Circuit Breaker Pattern)

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

نمط قاطع الدائرة البرمجي يفعل الشيء نفسه بالضبط. إنه يعمل كـ “بروكسي” أو وكيل بين الخدمة المستدعِية (Caller) والخدمة المستدعَاة (Dependency). هذا الوكيل يراقب حالة الطلبات، وله ثلاث حالات رئيسية:

1. الحالة المغلقة (Closed)

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

2. الحالة المفتوحة (Open)

هنا يتدخل البطل. القاطع الآن “مفتوح”. أي طلب جديد يأتي من الخدمة المستدعِية يتم رفضه فوراً (Fail Fast) دون محاولة الاتصال بالخدمة المتعطلة أصلاً. هذا الإجراء له فائدتان ذهبيتان:

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

يبقى القاطع في الحالة المفتوحة لمدة زمنية محددة (Cooldown period)، مثلاً 30 ثانية، ثم ينتقل إلى الحالة التالية.

3. الحالة نصف المفتوحة (Half-Open)

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

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

كيف نطبق هذا عملياً؟ (مع مثال كود)

الخبر السار هو أنك لست بحاجة لإعادة اختراع العجلة. معظم لغات البرمجة ومنصات العمل لديها مكتبات قوية جاهزة لتطبيق هذا النمط وغيره من أنماط المرونة (Resilience Patterns).

مثال باستخدام مكتبة Polly في .NET (C#)

مكتبة Polly هي الصديق الصدوق لكل مطور دوت نت يريد بناء أنظمة قوية. تطبيق قاطع الدائرة معها بسيط جداً. تخيل أن لديك عميل HTTP يستدعي خدمة خارجية:


// في ملف Startup.cs أو Program.cs
// لنفترض أن لدينا HttpClient لاسمه "ExternalApiService"

// تعريف سياسة قاطع الدائرة
var circuitBreakerPolicy = HttpPolicyExtensions
    .HandleTransientHttpError() // التعامل مع أخطاء الشبكة الشائعة
    .CircuitBreakerAsync(
        handledEventsAllowedBeforeBreaking: 5,   // اسمح بـ 5 أخطاء متتالية قبل فتح الدائرة
        durationOfBreak: TimeSpan.FromSeconds(30) // اترك الدائرة مفتوحة لمدة 30 ثانية
    );

// إضافة HttpClient مع تطبيق السياسة عليه
services.AddHttpClient("ExternalApiService", client =>
{
    client.BaseAddress = new Uri("https://api.externalservice.com/");
})
.AddPolicyHandler(circuitBreakerPolicy); // هنا السحر كله!

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

نصيحة من دار أبو عمر: لا تكتفِ بقاطع الدائرة!

قاطع الدائرة رائع، لكن قوته الحقيقية تظهر عندما تدمجه مع أنماط أخرى، خاصةً نمط “الاحتياطي” (Fallback).

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

باستخدام Polly مرة أخرى، يمكنك بسهولة تعريف سلوك احتياطي:


// سياسة احتياطية (Fallback)
var fallbackPolicy = Policy<HttpResponseMessage>
    .Handle<BrokenCircuitException>() // تعامل مع خطأ "الدائرة المفتوحة"
    .FallbackAsync(new HttpResponseMessage(HttpStatusCode.OK)
    {
        // إرجاع بيانات بديلة، ربما من الكاش أو بيانات ثابتة
        Content = new StringContent("{"data": "showing_default_recommendations"}")
    });

// دمج السياسات معاً (يجب أن يكون الاحتياطي هو الأخير)
var policyWrap = Policy.WrapAsync(fallbackPolicy, circuitBreakerPolicy);

// تطبيق السياسة المدمجة
services.AddHttpClient("ExternalApiService", ...)
    .AddPolicyHandler(policyWrap);

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

الخلاصة يا جماعة الخير

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

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

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

أبو عمر

سجل دخولك لعمل نقاش تفاعلي

كافة المحادثات خاصة ولا يتم عرضها على الموقع نهائياً

آراء من النقاشات

لا توجد آراء منشورة بعد. كن أول من يشارك رأيه!

آخر المدونات

الحوسبة السحابية

كانت فاتورة السحابة تلتهم ميزانيتنا: كيف أنقذتنا ‘ممارسات FinOps’ من جحيم الإنفاق غير المراقب؟

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

1 يونيو، 2026 قراءة المزيد
التوظيف وبناء الهوية التقنية

كان حسابي على GitHub مقبرة للمشاريع الميتة: كيف أنقذتني ‘المساهمات الاستراتيجية’ من جحيم السيرة الذاتية الفارغة؟

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

1 يونيو، 2026 قراءة المزيد
التكنلوجيا المالية Fintech

عملاؤنا كانوا أسرى لتطبيقات بنوكهم: كيف أنقذتنا ‘الخدمات المصرفية المفتوحة’ من جحيم الجزر المنعزلة؟

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

1 يونيو، 2026 قراءة المزيد
البنية التحتية وإدارة السيرفرات

كانت أعطالنا ألغازاً بلا خيوط: كيف أنقذنا ‘التتبع الموزع’ من جحيم البحث في سجلات متفرقة؟

في عالم الخدمات المصغرة (Microservices)، يصبح تتبع خطأ واحد كالبحث عن إبرة في كومة قش موزعة على عدة ولايات. في هذه المقالة، أسرد لكم قصتي...

1 يونيو، 2026 قراءة المزيد
ادارة الفرق والتنمية البشرية

كان الجميع يخشى قول ‘لا أعرف’: كيف أنقذتنا ‘ثقافة الأمان النفسي’ من جحيم الأخطاء الصامتة؟

في عالم البرمجة، قد يكون الخوف من قول 'لا أعرف' مدمراً. في هذه المقالة، أشارككم قصة حقيقية من تجربتي كقائد فريق، وكيف تحول فريقنا من...

1 يونيو، 2026 قراءة المزيد
اختبارات الاداء والجودة

كانت اختباراتنا خضراء لكنها عمياء: كيف أنقذنا ‘اختبار الطفرات’ (Mutation Testing) من جحيم الثقة الزائفة؟

أتذكر ذلك اليوم جيدًا، كل الاختبارات كانت خضراء، لكن كارثة كانت تلوح في الأفق. هذه قصتي مع الثقة العمياء في الاختبارات الآلية، وكيف كانت تقنية...

1 يونيو، 2026 قراءة المزيد
نصائح برمجية

كانت بياناتنا تتغير من تحت أقدامنا: كيف أنقذتنا ‘اللامتغيرية’ (Immutability) من جحيم الأعطال الجانبية؟

أشارككم قصة حقيقية من ميدان المعركة البرمجية، حين كاد خطأ بسيط بسبب تغيير البيانات (Mutability) أن يكلفنا الكثير. تعالوا نكتشف معاً مفهوم "اللامتغيرية" (Immutability) وكيف...

1 يونيو، 2026 قراءة المزيد
البودكاست