المستوى المطلوب: متوسط — تحتاج فهم أساسي لاستدعاءات الـ HTTP بين الخدمات، الـ async/await في JavaScript، وفكرة الـ thread pool. لو ما اشتغلتش قبل كده مع API خارجي ولا فهمت ليه السيرفر بيوقع لما خدمة تابعة تتعطّل، ابدأ بمقالات الأساسيات الأول وارجع للمقال ده بعدها.
لو خدمة الدفع عندك بتنادي Stripe، وStripe وقع لمدة دقيقة، كل طلب بيستنى رد بياكل thread أو connection لمدة 30 ثانية. مع 500 طلب في الثانية، الـ thread pool بيتسد في ثوان معدودة. النتيجة: السيرفر بتاعك بيرد ببطء على كل حاجة، حتى الـ endpoints اللي ملهاش علاقة بالدفع. Circuit Breaker بيحل المشكلة دي بسطر واحد من القرار: لما الخدمة الخارجية تكون فاشلة، بلاش تكلمها أصلاً.
المشكلة باختصار
المشكلة بسيطة في توصيفها، صعبة في تأثيرها. خدمة تابعة بتقع. الكود بتاعك مش عارف، فبيكمل يبعتلها طلبات. كل طلب بياخد وقت timeout كامل قبل ما يفشل. الـ thread pool بتاعك بيتسد. الطلبات السليمة من ميزات تانية بتفضل في الطابور. السيرفر كله بيرد ببطء، مش بس الميزة المعطلة. بعد دقيقتين، الـ load balancer بيشيل السيرفر من الـ pool لأنه health check بيفشل. السيرفر التاني بياخد كل الحمل، بيقع كمان. اللي بدأ مشكلة في خدمة Stripe بقى outage في كل النظام.
المثال البسيط: عداد الكهرباء في البيت
تخيّل عندك تكييف وقع فيه short circuit. لو ما فيش مفتاح حماية في عداد الكهرباء، التيار هيكمل يتدفق وهيولّد حرارة وممكن يولّع حريقة في الشقة كلها. مفتاح الحماية بيقطع التيار في أقل من ثانية لما يحس بالخطأ، وبيفصل لحد ما حد يأكد إن الجهاز اتصلح ويدوس Reset.
Circuit Breaker في الكود بيشتغل بنفس المنطق بالظبط. هو طبقة بين الخدمة بتاعتك والخدمة التانية. بيعد الفشل. لو وصل لحد معين، بيقفل المفتاح. أي طلب جديد بيرجع فشل فوري بدون ما يحاول أصلاً يكلم الخدمة المعطلة. بعد فترة، بيسمح بطلب واحد يجرّب يعدّي. لو نجح، بيرجع الوضع لطبيعته. لو فشل، بيقفل تاني.
التعريف العلمي الدقيق
Circuit Breaker pattern طرحه Michael Nygard في كتابه "Release It!" سنة 2007، وبقى من أساسيات الـ resilience engineering في الأنظمة الموزّعة. تقنيًا، هو state machine بثلاث حالات:
- Closed: الوضع الطبيعي. الطلبات بتعدّي بشكل عادي للخدمة التابعة. الـ breaker بيعد عدد الفشلات في نافذة زمنية محددة.
- Open: الفشلات تخطّت الحد المسموح به (threshold). أي طلب بيرجع فشل فوري بدون ما يستدعي الخدمة التابعة. بيستمر في الحالة دي لفترة محددة (reset timeout).
- Half-Open: بعد انتهاء فترة الـ timeout، بيسمح بعدد محدود من الطلبات (probe requests) تجرّب الخدمة. لو نجحت، بيرجع لـ Closed. لو فشلت، بيرجع لـ Open ويعيد العداد.
الفلسفة الأساسية: fail fast بدل fail slow. فشل سريع بيخلي السيستم يستجيب للضغط. فشل بطيء بياكل الموارد ويعدّي العدوى لباقي النظام.