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

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

كنا وقتها شغالين على نظام ضخم مبني على معمارية الخدمات المصغرة (Microservices). كل شيء كان ماشي زي الحلاوة، والنظام شغال والحمد لله. لحد ما إجا يوم “الجمعة السوداء” (Black Friday)، اليوم اللي كل شركات التجارة الإلكترونية بتستناه وبتخاف منه بنفس الوقت. الضغط على السيرفرات كان أسطوري، وآلاف الطلبات في الثانية الواحدة.

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

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

هذاك اليوم، أقسمنا إنه هاي الحادثة ما رح تتكرر. ومن هنا بدأت رحلتنا مع نمط تصميم غيّر طريقة تفكيرنا في بناء الأنظمة المرنة: نمط قاطع الدائرة (Circuit Breaker).

ما هو جحيم الأعطال المتتالية (Cascading Failures)؟

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

في عالم البرمجيات والخدمات المصغرة، يحدث هذا عندما:

  1. خدمة (خلينا نسميها “خدمة التوصيات”) تصبح بطيئة أو تتوقف عن العمل.
  2. الخدمات الأخرى (مثل “خدمة المنتج”) التي تستدعيها، تظل تنتظر الرد لفترة طويلة (Timeout).
  3. أثناء فترة الانتظار، كل طلب يستهلك موارد ثمينة (مثل Thread في الـ Thread Pool).
  4. مع زيادة عدد الطلبات العالقة، يتم استهلاك كل الموارد المتاحة في “خدمة المنتج”.
  5. الآن، “خدمة المنتج” نفسها أصبحت غير قادرة على خدمة أي طلبات جديدة، حتى تلك التي لا علاقة لها بـ “خدمة التوصيات”.
  6. العدوى تنتقل… أي خدمة أخرى تعتمد على “خدمة المنتج” ستبدأ بالفشل هي الأخرى. وهكذا، ينهار النظام بأكمله كأحجار الدومينو.

المشكلة الكبرى هي أن النظام يظل يحاول “بعناد” استدعاء الخدمة الفاشلة مع كل طلب جديد، مما يزيد الطين بلة ويمنع الخدمة الفاشلة من التعافي، لأنه ببساطة “مخنوقة” بالطلبات.

طوق النجاة: نمط قاطع الدائرة (Circuit Breaker)

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

هذا الحارس يراقب صحة استدعاءات الشبكة، وعندما يكتشف أن الخدمة المستدعاة تفشل بشكل متكرر، “يفتح الدائرة” (Open the circuit). أي أنه يمنع إرسال أي طلبات جديدة لتلك الخدمة لفترة زمنية محددة، وبدلاً من ذلك، يفشل فوراً (Fail Fast). هذا التصرف الذكي يحقق هدفين عظيمين:

  1. حماية النظام المستدعي: يمنعه من استهلاك موارده في انتظار خدمة ميتة.
  2. إعطاء فرصة للخدمة الفاشلة: يمنحها وقتاً لتتعافى وتتنفس بدلاً من خنقها بمزيد من الطلبات.

كيف يعمل قاطع الدائرة؟ الحالات الثلاث

قاطع الدائرة له ثلاث حالات رئيسية، يتنقل بينها بذكاء:

1. مغلق (Closed):
هذا هو الوضع الطبيعي. يتم تمرير جميع الطلبات إلى الخدمة المستهدفة. في هذا الوضع، يقوم القاطع بحساب عدد حالات الفشل (مثل الأخطاء أو انتهاء المهلة). إذا تجاوز عدد حالات الفشل حداً معيناً (Threshold) خلال فترة زمنية محددة، ينتقل القاطع إلى حالة “مفتوح”.

2. مفتوح (Open):
عندما “تنفجر” الدائرة. في هذا الوضع، يتم رفض جميع الطلبات إلى الخدمة المستهدفة فوراً دون محاولة الاتصال بها. يتم إرجاع خطأ فوري للخدمة المستدعية. يبقى القاطع في هذا الوضع لفترة زمنية محددة مسبقاً (Cooldown period). هذا يمنح الخدمة المتعثرة وقتاً للتعافي.

3. شبه مفتوح (Half-Open):
بعد انتهاء فترة التهدئة في الوضع المفتوح، ينتقل القاطع إلى هذا الوضع الحذر. يسمح القاطع بمرور طلب واحد فقط (أو عدد قليل جداً) إلى الخدمة المستهدفة كـ “جس نبض”.
– إذا نجح هذا الطلب التجريبي، يفترض القاطع أن الخدمة قد تعافت، ويعود إلى وضع “مغلق” لتعود الحياة إلى طبيعتها.
– إذا فشل الطلب التجريبي، يستنتج القاطع أن المشكلة لا تزال قائمة، فيعود إلى وضع “مفتوح” مرة أخرى ليبدأ فترة تهدئة جديدة.

لنطبق الأمر عملياً: مثال كود بسيط

الكلام النظري جميل، لكن “الشيخ جوجل” والـ “Stack Overflow” ما بقصروا. خلينا نشوف كيف ممكن نطبق هذا النمط عملياً. من أشهر المكتبات اللي بتوفر هاي الوظيفة هي مكتبة Polly في عالم الـ .NET (C#)، وهناك مكتبات مماثلة في كل لغات البرمجة (مثل Hystrix في Java أو aio-circuitbreaker في Python).

هنا مثال بسيط باستخدام C# ومكتبة Polly لتوضيح الفكرة:


// C# with Polly Library Example

// تعريف سياسة قاطع الدائرة
// رح "نفتح" الدائرة إذا حدث 5 أخطاء متتالية
// ورح نضل في الوضع المفتوح لمدة 30 ثانية قبل ما نجرب مرة ثانية
var circuitBreakerPolicy = Policy
    .Handle<HttpRequestException>() // حدد نوع الأخطاء اللي رح نعدها
    .CircuitBreakerAsync(
        exceptionsAllowedBeforeBreaking: 5, // عدد الأخطاء المسموح بها قبل فتح الدائرة
        durationOfBreak: TimeSpan.FromSeconds(30), // مدة بقاء الدائرة مفتوحة
        onBreak: (exception, timespan) => 
        {
            Console.WriteLine("الدائرة انفتحت! ما رح نرسل طلبات لمدة 30 ثانية.");
        },
        onReset: () => 
        {
            Console.WriteLine("الدائرة رجعت تسكرت. الخدمة شكلها رجعت تشتغل.");
        },
        onHalfOpen: () => 
        {
            Console.WriteLine("الدائرة في وضع شبه مفتوح، رح نجرب نرسل طلب واحد.");
        }
    );

// استخدام السياسة عند استدعاء خدمة خارجية
try
{
    // HttpClient هو المسؤول عن إرسال طلبات الـ HTTP
    var httpClient = new HttpClient();
    
    // تنفيذ الطلب من خلال قاطع الدائرة
    HttpResponseMessage response = await circuitBreakerPolicy.ExecuteAsync(
        () => httpClient.GetAsync("https://api.example.com/recommendations")
    );

    // ... التعامل مع الاستجابة الناجحة
}
catch (BrokenCircuitException)
{
    // هذا الخطأ يحدث فوراً عندما تكون الدائرة مفتوحة
    // هنا بنقدر نرجع بيانات بديلة أو رسالة للمستخدم
    Console.WriteLine("الخدمة غير متاحة حالياً، حاول لاحقاً. (رجعنا من الكاتش فوراً)");
    // return GetDefaultRecommendations(); // مثال: إرجاع بيانات بديلة
}
catch (HttpRequestException)
{
    // هذا الخطأ يحدث عندما تكون الدائرة مغلقة ولكن الطلب فشل
    Console.WriteLine("فشل الطلب أثناء محاولة الاتصال بالخدمة.");
}

هذا الكود البسيط يغلف استدعاء الشبكة بسياسة قاطع الدائرة. لاحظ كيف أنه يفصل منطق “مرونة النظام” عن منطق العمل الأساسي، وهذا بحد ذاته ممارسة ممتازة.

نصائح من قلب المعركة (خبرة أبو عمر)

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

1. إعداداتك ليست قرآناً منزلاً (Configure, Don’t Hardcode)

الأرقام اللي حطيناها في المثال (5 محاولات، 30 ثانية) هي مجرد مثال. لا تقم أبداً بتثبيت هذه القيم في الكود (Hardcoding). يجب أن تكون هذه الإعدادات قابلة للتغيير من خلال ملفات الإعدادات (Configuration files) أو متغيرات البيئة (Environment variables). هذا يسمح لك بتعديل سلوك القاطع في بيئة الإنتاج (Production) بدون الحاجة لإعادة نشر الكود. لكل خدمة ظروفها، وما يصلح لخدمة قد لا يصلح لأخرى.

2. ماذا تفعل عندما تكون الدائرة مفتوحة؟ (Implement Fallbacks)

أن تفشل بسرعة (Fail Fast) هو نصف الحل فقط. النصف الآخر هو: ماذا تقدم للمستخدم بدلاً من رسالة خطأ قبيحة؟ هذا ما يسمى بالـ “Fallback Logic”.
– إذا كانت خدمة التوصيات معطلة، هل يمكن عرض منتجات من نفس الفئة كبديل؟
– هل يمكن عرض بيانات محفوظة من آخر استدعاء ناجح (Cached Data)؟
– في أسوأ الأحوال، هل يمكن إخفاء قسم التوصيات بالكامل من الصفحة بدلاً من إظهار خطأ؟
الهدف هو “التدهور برشاقة” (Graceful Degradation). المستخدم قد لا يلاحظ حتى أن هناك مشكلة.

3. راقب قواطعك كما تراقب أولادك (Monitoring & Alerting)

قاطع الدائرة هو مؤشر حيوي لصحة نظامك. يجب أن يكون لديك لوحة مراقبة (Dashboard) تظهر حالة كل قواطع الدائرة في نظامك (مغلق، مفتوح، شبه مفتوح). عندما “يفتح” قاطع دائرة معين، يجب أن يطلق ذلك إنذاراً (Alert) لفريق العمل فوراً. هذا الإنذار يعني: “يا جماعة، في خدمة عندكم بتعاني، روحوا شوفوا شو قصتها قبل ما تصير كارثة”. اللي ما بتعرفه عن نظامك، ممكن يقتلك.

4. ليس كل القواطع متساوية (Context is Key)

عامل كل خدمة حسب أهميتها. قاطع الدائرة الذي يحمي “خدمة الدفع” (Payment Service) يجب أن يكون له إعدادات مختلفة تماماً عن الذي يحمي “خدمة صور المستخدم” (User Avatar Service). خدمة الدفع قد تحتاج إلى سياسة إعادة محاولة (Retry Policy) أكثر حذراً، بينما خدمة الصور يمكن أن تتحمل الفشل بسهولة أكبر مع Fallback بسيط (مثل عرض صورة افتراضية).

الخلاصة: من الفوضى إلى المرونة

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

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

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

أبو عمر

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

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

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

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

آخر المدونات

التوظيف وبناء الهوية التقنية

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

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

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

من كوابيس الامتثال اليدوي إلى ثورة الأتمتة: كيف أنقذتنا ‘التكنولوجيا التنظيمية’ (RegTech)؟

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

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

كنا نعمل في الظلام: كيف أنقذتنا ‘المراقبة الشاملة’ (Observability) من جحيم البحث عن أسباب الأعطال؟

أشارككم قصة حقيقية عن ليلة كاد فيها نظامنا أن ينهار، وكيف انتقلنا من التخمين العشوائي في الظلام إلى التشخيص الدقيق في ثوانٍ بفضل مفهوم "المراقبة...

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

كان فريقنا على وشك الانهيار بعد رحيل مهندس واحد: كيف أنقذتنا ‘مصفوفة المهارات’ من جحيم ‘عامل الحافلة’ (Bus Factor)؟

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

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

كانت تغطية الكود 100% خادعة: كيف كشف ‘الاختبار الطفري’ (Mutation Testing) عن عيوب اختباراتنا الصامتة؟

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

18 مايو، 2026 قراءة المزيد
أدوات وانتاجية

كنا نغرق في الكود المتكرر: كيف حول ‘مساعد الذكاء الاصطناعي’ (Copilot) تركيزنا من الكتابة إلى الإبداع؟

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

18 مايو، 2026 قراءة المزيد
أتمتة العمليات

كانت بيئاتنا غير متطابقة: كيف أنقذنا “الكود كبنية تحتية” (IaC) من جحيم “لكنه يعمل على جهازي”؟

أتذكر تلك الليلة جيدًا، ليلة كادت أن تودي بمشروعنا إلى الهاوية بسبب جملة واحدة: "بس شغّال عندي!". في هذه المقالة، سأشارككم يا جماعة كيف انتقلنا...

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