المستوى: متوسط — هذا المقال للمطورين اللي عندهم خبرة سنة على الأقل في PostgreSQL، وعارفين Node.js أو Python كويس، وفاهمين معنى trigger وtransaction. لو لسه مبتدئ في SQL، اقرأ أول قسمين بس واتفرّج على الكود من بعيد.
لو خدمتك بتفتح SELECT كل ثانيتين علشان تلحق آخر تعديل في جدول shipments، انت بتدفع 3 تكاليف خفية: load زيادة على الـ DB، latency 1 إلى 2 ثانية في وش المستخدم، وكود polling هش بيكسر مع كل scale-up. PostgreSQL عنده آلية built-in من سنة 2000 اسمها LISTEN/NOTIFY بترسل event من الـ DB للتطبيق في أقل من 18 مللي ثانية، بدون Redis ولا RabbitMQ ولا Kafka.
المشكلة باختصار: ليه polling بيقتل تطبيقك في الإنتاج
خد سيناريو واقعي: تطبيق متابعة شحنات. السائق بيحدّث موقعه في جدول shipments كل 5 ثواني، والعميل بيشوف الموقع على خريطة في المتصفح. الطريقة الشائعة اللي بتقابلها في أكتر من 70% من الـ codebases العربية اللي عملنا فيها code review:
- المتصفح بيبعت
GET /shipment/123كل 3 ثواني. - السيرفر بيعمل
SELECT * FROM shipments WHERE id=123على كل request. - لو عندك 8,000 عميل بيتابعوا شحنات في نفس الوقت، ده 2,667 query/ثانية، 96% منهم بيرجّعوا بيانات لم تتغيّر.
الـ DB بتاكل CPU في الفاضي، والعميل بيشوف التحديث متأخر 1.5 ثانية في المتوسط، وفاتورة السحابة بتعلى من غير سبب. الحل مش بزيادة index ولا بإضافة Redis cache — الحل إن الـ DB هي اللي تقولك "في تحديث" بدل ما إنت تسأل.
المثال البسيط: جرس البيت مقابل سؤال "حد طرق؟" كل دقيقة
تخيل إنك قاعد في شقتك وعايز تعرف ساعة ما حد ييجي. عندك خيارين:
- polling: تقوم كل دقيقة وتفتح الباب وتشوف. هتتعب، هتفوت اللي طرق ومشي بين فحصين، وفي 99% من المرات هتلاقي الباب فاضي.
- الجرس (NOTIFY): ركّب جرس. هو اللي ينبهك ساعة ما حد ييجي بالظبط. صفر طاقة ضايعة، صفر تأخير.
LISTEN/NOTIFY ببساطة جرس باب لقاعدة البيانات. التطبيق بيقول "أنا مستمع على القناة دي"، والـ trigger في الـ DB بيدق الجرس لما يحصل تعديل.
التعريف العلمي الدقيق
حسب توثيق PostgreSQL 16 الرسمي (postgresql.org/docs/16/sql-notify.html)، LISTEN/NOTIFY هي آلية asynchronous inter-process messaging مدمجة من إصدار 7.0 سنة 2000 ومحسّنة جذرياً في إصدار 9.0 لما نقلوا الـ queue من نظام الملفات لذاكرة مشتركة (SLRU buffer).
الفكرة بالتفاصيل:
NOTIFY channel, 'payload'بيبعت رسالة نصية لقناة محددة. الحجم الأقصى للـ payload هو 8000 byte (محدد بـNAMEDATALENفي source code).- أي client عمل
LISTEN channelبيستلم الرسالة عند COMMIT (لو الـ NOTIFY جوه transaction) أو فوراً (لو برّاها). - الـ queue الداخلي بيتخزن في pg_notification_queue والحد الأقصى 8GB. فوق كده PostgreSQL يرفض NOTIFY جديد ويرجّع error .