بناء نظام إشعارات Real-Time باستخدام RabbitMQ وWebSockets خطوة بخطوة

بناء نظام إشعارات Real-Time باستخدام RabbitMQ وWebSockets خطوة بخطوة

في هذا المقال سنبني نظام إشعارات لحظي (Real-Time Notifications) باستخدام RabbitMQ كـ Message Broker، وWebSockets كقناة اتصال مستمرة مع المتصفح، بحيث تصل التنبيهات فورياً للمستخدمين بدون إعادة تحميل الصفحة.

المقال موجه للمطورين الذين لديهم معرفة أساسية بالباك إند (Python/Node.js/غيرها)، ويريدون فهم كيفية ربط RabbitMQ real time notifications مع WebSockets في بنية منظمة وقابلة للتوسع.

إذا كنت مهتماً أكثر بتكامل RabbitMQ مع FastAPI أو العمل مع WebSockets في FastAPI، يمكنك لاحقاً الرجوع إلى:

لماذا نحتاج RabbitMQ + WebSockets معاً؟

قبل الدخول في التفاصيل، لنفهم مشكلة الإشعارات اللحظية في الأنظمة الحديثة:

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

هنا تأتي فكرة الجمع بين:

  • RabbitMQ: للتعامل مع الأحداث (Messages) بين الخدمات بشكل آمن وموثوق، مع إمكانيات Routing وQueues وExchanges.
  • WebSockets: للحفاظ على اتصال مستمر بين السيرفر والعميل (المتصفح / التطبيق)، بحيث يمكن إرسال الإشعارات فورياً بدون Polling.

النتيجة: بنية نظيفة، فيها فصل واضح بين توليد الإشعار (من أي خدمة) وإرسال الإشعار فعلياً للمستخدم عبر WebSocket.

معمارية نظام RabbitMQ Real-Time Notifications

لنصمم أولاً المعمارية (Architecture) قبل كتابة أي كود. الفكرة الأساسية:

  1. خدمة أو أكثر في الباك إند ترسل رسالة إلى RabbitMQ عندما يحدث حدث يتطلب إشعاراً.
  2. لدينا Notification Service (قد تكون خدمة مستقلة) تقوم بـ:
    • الاستماع (Consume) للرسائل من RabbitMQ.
    • تحديد المستخدم أو المجموعة المستهدفة.
    • إرسال الإشعار عبر WebSocket للمستخدمين المتصلين.
  3. في الواجهة الأمامية (Front-end)، كل متصفح يفتح اتصال WebSocket مع السيرفر، ويرسل مثلاً Token أو User ID للتعريف بنفسه.
  4. عند وصول إشعار من RabbitMQ، يتم تمريره فوراً عبر WebSocket إلى التبويبات / الأجهزة الخاصة بذلك المستخدم.

يمكن الاستفادة من البنية العامة لأنظمة Real-Time الموضحة في مقال: بنية أنظمة الدردشة اللحظية: من WebSockets إلى Message Queues، فهي مشابهة جداً لما نريده هنا.

تجهيز RabbitMQ لقنوات الإشعارات

أول خطوة عملية هي تعريف كيفية تمرير رسائل الإشعار داخل RabbitMQ. غالباً سنحتاج:

  • Exchange مخصص للإشعارات، وليكن اسمه notifications.exchange.
  • Queue أو أكثر لكل نوع من المستهلكين (مثلاً: إشعارات الويب، إشعارات الموبايل، Logging…).

اختيار نوع الـ Exchange

أكثر الأنواع شيوعاً لحالة الإشعارات:

  • direct exchange: مفيد حين يكون Routing Key واضح، مثل: user.123 أو email.
  • topic exchange: مرن أكثر، يمكنك استخدام أنماط مثل: notifications.user.123 أو notifications.group.admins.

في أنظمة الإشعارات المتوسطة إلى الكبيرة، topic exchange خيار ممتاز. مثلاً:

  • Exchange: notifications.exchange من نوع topic.
  • سطر التوجيه (Routing Key): user.<user_id> أو group.<group_name>.

مثال هيكل رسالة الإشعار

الرسالة التي سترسلها الخدمات إلى RabbitMQ يفضل أن تكون JSON موحد الشكل، مثل:

{
  "user_id": 123,
  "title": "لديك رسالة جديدة",
  "body": "قام أحمد بإرسال رسالة لك",
  "type": "new_message",
  "link": "/messages/456",
  "created_at": "2026-04-13T10:00:00Z"
}

يمكن أيضاً إضافة حقول أخرى مثل الأولوية، أو بيانات إضافية حسب نوع الإشعار.

بناء خدمة الإشعارات (Notification Service)

هذه الخدمة هي قلب نظام RabbitMQ real time notifications. وظيفتها:

  1. فتح اتصال مع RabbitMQ.
  2. الاستماع (Consume) لرسائل الإشعارات من Queue معينة.
  3. تحويل الرسالة إلى إشعار WebSocket للمستخدم المستهدف.

منطق العمل العام

لنفرض أن لدينا Queue اسمها notifications.websocket.queue مربوطة بالـ Exchange باستخدام نمط Routing مثل user.*. منطق العمل:

  1. الخدمة تستهلك الرسائل من notifications.websocket.queue.
  2. كل رسالة تحتوي على user_id أو قائمة user_ids.
  3. الخدمة تبحث في خريطة الاتصالات النشطة (In-memory أو Redis) عن كل اتصال WebSocket يخص ذلك المستخدم.
  4. ترسل الإشعار على شكل JSON عبر WebSocket.

يمكن كتابة هذه الخدمة بأي لغة: Python، Node.js، Go، إلخ. المهم هو الحفاظ على:

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

إدارة اتصالات WebSockets وربطها بالمستخدمين

حتى يستطيع السيرفر إرسال إشعار للمستخدم الصحيح، يجب أن يعرف:

  • أي Connection (WebSocket) يخص أي User ID.
  • ماذا نفعل عندما يفتح المستخدم أكثر من تبويب أو جهاز في نفس الوقت.

خطوة 1: فتح اتصال WebSocket من الواجهة الأمامية

في تطبيق الويب (React/Vue/Angular أو حتى Vanilla JS)، نفتح اتصال WebSocket إلى السيرفر:

const socket = new WebSocket("wss://example.com/ws/notifications");

socket.onopen = () => {
  // إرسال توكن JWT أو Session ID للتعريف بالمستخدم
  socket.send(JSON.stringify({
    type: "auth",
    token: "USER_JWT_TOKEN"
  }));
};

socket.onmessage = (event) => {
  const data = JSON.parse(event.data);
  // التعامل مع الإشعار
  console.log("New notification:", data);
};

خطوة 2: تعريف المستخدم على السيرفر

في السيرفر، أول رسالة من العميل ستكون من نوع auth. المنطق:

  1. استقبال الرسالة.
  2. التحقق من صحة token (JWT أو Session).
  3. استخراج user_id.
  4. تخزين Connection الحالي تحت هذا user_id.

يمكن تمثيل الخريطة كالتالي (كمبدأ عام):

user_connections = {
  123: [ws_connection_1, ws_connection_2],
  456: [ws_connection_3]
}

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

أين نخزن خريطة الاتصالات؟

  • أصغر نظام: في الذاكرة (in-memory) داخل عملية السيرفر نفسها، يصلح للتجارب أو الأنظمة الصغيرة.
  • نظام موزع: خزن في Redis أو خادم Pub/Sub منفصل، حتى تتشارك عدة Instances من السيرفر نفس المعلومات عن الاتصالات النشطة.

في الأنظمة القابلة للتوسع، ستحتاج بنية أقرب لما شرحناه في: تصميم نظام Notifications قابل للتوسع باستخدام Message Queues.

تدفق الإشعار كاملاً: من الحدث إلى شاشة المستخدم

لنمر على السيناريو كامل خطوة بخطوة، لنفهم كيف يعمل نظام RabbitMQ real time notifications في حالة حقيقية، مثل: وصول رسالة جديدة في نظام دردشة.

  1. مستخدم (أحمد) يرسل رسالة إلى مستخدم آخر (سارة).
  2. خدمة الدردشة (Chat Service) تخزن الرسالة في قاعدة البيانات بنجاح.
  3. بعد التخزين، تقوم الخدمة بإرسال رسالة إلى RabbitMQ:
    {
      "user_id": 2001,             // سارة
      "title": "رسالة جديدة",
      "body": "أحمد: كيف حالك؟",
      "type": "chat_message",
      "link": "/chat/room/123",
      "created_at": "2026-04-13T10:20:00Z"
    }
  4. الرسالة تذهب إلى Exchange notifications.exchange مع Routing Key user.2001.
  5. Queue notifications.websocket.queue مربوطة مع نمط user.*، فتصلها الرسالة.
  6. Notification Service تستهلك الرسالة، تقرأ user_id = 2001.
  7. الخدمة تبحث في خريطة الاتصالات، تجد أن سارة متصلة على WebSocket في تبويب واحد مثلاً.
  8. الخدمة ترسل JSON الإشعار إلى اتصال WebSocket:
{
  "event": "notification",
  "data": {
    "title": "رسالة جديدة",
    "body": "أحمد: كيف حالك؟",
    "type": "chat_message",
    "link": "/chat/room/123",
    "created_at": "2026-04-13T10:20:00Z"
  }
}
  1. العميل (المتصفح) يستقبل الرسالة في onmessage، يعرض إشعار في الواجهة (Badge، Popup، تغيير لون الأيقونة…).

التعامل مع الأخطاء والموثوقية

واحدة من أهم مميزات استخدام RabbitMQ في نظام الإشعارات هي تحسين الموثوقية والتعامل مع الفشل الجزئي.

ماذا لو فشل إرسال الإشعار عبر WebSocket؟

أسباب الفشل قد تكون:

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

بعض الاستراتيجيات للتعامل مع ذلك:

  • تخزين الإشعارات في قاعدة البيانات: بحيث حتى لو لم يكن المستخدم متصلاً، سيجد الإشعارات لاحقاً في مركز الإشعارات (Notifications Center) عندما يفتح التطبيق.
  • إعادة المحاولة: في بعض الحالات، إذا كان الخطأ عابر، يمكن تأجيل الإشعار وإعادة المحاولة مرة أخرى لفترة قصيرة.
  • إرسال بديل (Fallback): مثل إرسال Email أو Push Notification للموبايل إذا كان الحدث مهم جداً.

من ناحية RabbitMQ نفسه، تأكد من:

  • استخدام Acknowledgements (ACK) للرسائل بعد معالجتها بنجاح.
  • إعادة الرسائل إلى Queue أو إرسالها إلى Dead Letter Queue في حال الفشل المتكرر.

الأمان في نظام الإشعارات اللحظية

لأننا نتعامل مع WebSockets وMessages، يجب الانتباه لعدة نقاط أمنية:

  • توثيق اتصال WebSocket:
    • لا تقبل اتصالاً بدون توثيق.
    • استخدم JWT أو Cookies آمنة للتحقق من هوية المستخدم.
  • التحقق من صلاحيات الإشعار:
    • لا ترسل إشعاراً يخص مستخدم (أ) إلى مستخدم (ب).
    • تأكد من أن user_id من RabbitMQ يتطابق فعلياً مع الاتصال الحالي.
  • تأمين RabbitMQ نفسه:
    • استخدم اسم مستخدم وكلمة مرور قوية لـ RabbitMQ.
    • حدد Permissions لمن يمكنه النشر (Publish) ومن يمكنه الاستهلاك (Consume).
  • تشفير الاتصال:
    • استخدم WSS بدلاً من WS (أي WebSocket فوق HTTPS).
    • إذا أمكن، استخدم TLS لربط الخدمات بـ RabbitMQ.

نصائح عملية لتصميم نظام RabbitMQ Real Time Notifications قابل للتوسع

عندما يكبر النظام ويبدأ في استقبال آلاف أو ملايين الإشعارات في اليوم، القابلية للتوسع تصبح أولوية.

1. افصل طبقة الإشعارات عن منطق الأعمال

دائماً اجعل إرسال الإشعار عملية غير متزامنة (Asynchronous) عن منطق الأعمال:

  • خدمة الأعمال (مثل Chat أو Orders) ترسل حدث إلى RabbitMQ.
  • خدمة الإشعارات (Notification Service) تتعامل مع الإرسال للمستخدمين.

هذا الفصل يسهل صيانة الكود، ويسمح لك بتغيير طريقة الإرسال (WebSockets، Email، Push…) بدون لمس الخدمات الأخرى.

2. استخدم أكثر من Queue عند الحاجة

يمكنك توزيع الأحمال هكذا:

  • notifications.websocket.queue: للإشعارات اللحظية على الويب.
  • notifications.email.queue: للإشعارات عبر البريد.
  • notifications.mobile.queue: لـ Push Notifications.

كل Queue يمكن أن تستهلكها خدمة مستقلة، وبذلك يمكن توسيع كل نوع إشعارات بشكل منفصل.

3. قسّم الإشعارات حسب الأهمية

بعض الإشعارات حرجة (Critical) ويجب أن تصل في أعلى أولوية، مثل: عمليات مالية، تنبيهات أمان، إلخ. يمكنك:

  • استخدام Exchange وQueue مخصص للإشعارات الحرجة.
  • تعيين عدد أكبر من المستهلكين (Consumers) لهذه الـ Queue.

4. راقب أداء RabbitMQ وخدمات الإشعارات

بعض المؤشرات المهمة:

  • طول الـ Queues (هل هناك تراكم كبير؟)
  • معدل الاستهلاك (Messages/sec)
  • معدل الأخطاء والفشل في الإرسال

الـ Management Plugin في RabbitMQ يقدم واجهة ممتازة للمراقبة، ويمكنك أيضاً إضافة Prometheus + Grafana لو أردت مراقبة أعمق.

دمج ما تعلمته مع مشاريعك الحالية

بعد فهم فكرة RabbitMQ real time notifications مع WebSockets، تستطيع تطبيقها في عدة سيناريوهات:

  • نظام دردشة لحظية (Real-Time Chat).
  • لوحة تحكم تعرض إحصاءات أو تقارير تتحدث تلقائياً.
  • إشعارات عمليات بيع وشراء في متجر إلكتروني.
  • تنبيهات نظام Monitoring أو Logging للمطورين.

لو كنت تعمل مع Django أو FastAPI، يمكنك الجمع بين مقالات:

وتبني منها نظام إشعارات متكامل بالاعتماد على ما شرحناه هنا من معمارية وخطوات.

الخلاصة

بناء نظام إشعارات Real-Time باستخدام RabbitMQ وWebSockets يمنحك:

  • إرسال لحظي للإشعارات للمستخدمين بدون Polling.
  • فصل واضح بين منطق الأعمال وبنية الإشعارات.
  • قابلية عالية للتوسع مع إمكانية التعامل مع آلاف الإشعارات في الثانية.
  • مرونة في إضافة قنوات إشعار جديدة (Email، Push، SMS) دون تغيير المعمارية الأساسية.

الخطوات الأساسية التي رأيناها:

  1. تصميم Exchange وQueues في RabbitMQ للإشعارات.
  2. توحيد شكل رسالة الإشعار (JSON) من الخدمات المختلفة.
  3. بناء Notification Service لاستهلاك الرسائل وربطها باتصالات WebSockets.
  4. إدارة اتصالات WebSockets وربطها بالمستخدمين المصادق عليهم.
  5. معالجة الأخطاء، وضمان موثوقية الإشعارات، وتأمين الاتصالات.

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

حول المحتوى:

شرح عملي لبناء نظام إشعارات لحظية باستخدام RabbitMQ وربطه مع WebSockets لإرسال التنبيهات فورياً للمستخدمين.

هل كان هذا مفيدًا لك؟

أضف تعليقك