يا أهلاً وسهلاً فيكم يا جماعة الخير. اسمي أبو عمر، وبشتغل في هالمجال، مجال البرمجة وتطوير البرمجيات، من سنين طويلة. اليوم حابب أحكي لكم قصة صارت معي ومع فريقي قبل كم سنة، قصة علمتنا درس مهم عن الكفاءة وكيف إنه اختيار الأداة الصح ممكن يوفر عليك “وجعة راس” وموارد أنت أولى فيها.
كنا شغالين على مشروع متجر إلكتروني كبير، وكان جزء أساسي من المشروع هو الربط مع نظام إدارة مخزون لأحد أكبر الموردين. هالمورد عنده آلاف المنتجات، والأسعار وكميات المخزون بتتغير بشكل مجنون خلال اليوم. مهمتنا كانت بسيطة على الورق، لكنها جحيم في التنفيذ: لازم نعرض في متجرنا آخر تحديث للسعر والكمية بشكل فوري. أي تأخير ممكن يعني إنه نبيع منتج خلص من المخزون، أو نبيعه بسعر قديم ونخسر فلوس. مصيبة يعني.
في البداية، وبكل سذاجة المبتدئين (مع إنه ما كنا مبتدئين وقتها!)، قلنا الحل بسيط: بنعمل “Polling”. يعني بنخلي سيرفرنا كل 10 ثواني يبعت طلب لـ API المورد يسأله: “يا عمي، شو صار في المنتج الفلاني؟ تغير سعره؟ تغير مخزونه؟”. وبعدها قللنا المدة لـ 5 ثواني عشان نكون “Real-time” أكثر. كانت النتيجة كارثية! السيرفر تبعنا صار زي واحد راكض في ماراثون وهو حامل أثقال. استهلاك المعالج (CPU) في السما، تكلفة نقل البيانات زادت، والأدهى من هيك، 99% من الطلبات اللي بنبعتها كانت بترجع بنفس الجواب: “ما في إشي جديد!”. كان الوضع أشبه بطفل صغير في السيارة كل شوي بسأل أبوه: “وصلنا؟… طيب هسا وصلنا؟… طيب هسا؟”. جحيم بكل ما للكلمة من معنى.
لحد ما في يوم، وإحنا في اجتماع طارئ لمناقشة فواتير السيرفرات اللي بتزيد، واحد من الشباب صرخ: “يا جماعة، إحنا بنشتغل غلط! ليش إحنا اللي نسأل؟ ليش ما نخلي المورد هو اللي يخبرنا لما يصير تحديث؟”. وهنا كانت لحظة التنوير. هنا دخلت الـ “Webhooks” على الخط وأنقذت الموقف. ومن يومها، صرت من أكبر المدافعين عن هذي التقنية الرائعة.
ما هو الاستقصاء (Polling)؟ جحيم الطلبات المتكررة
قبل ما نحكي عن المنقذ، خلينا نفصّل أكتر في المشكلة. الـ Polling أو “الاستقصاء” هو أسلوب برمجي يعتمد على أن يقوم العميل (Client)، وهو السيرفر تبعنا في القصة، بسؤال الخادم (Server)، وهو نظام المورد، بشكل متكرر على فترات زمنية ثابتة لمعرفة ما إذا كان هناك أي تحديثات جديدة.
كيف يعمل الـ Polling؟
الفكرة بسيطة جداً. العميل يبرمج نفسه على إرسال طلب HTTP (عادةً GET) كل ‘س’ من الثواني. الخادم يستقبل الطلب، يتحقق من وجود بيانات جديدة، ويرسل رداً. العميل يستقبل الرد ويتصرف بناءً عليه. ثم ينتظر ‘س’ ثواني أخرى ويعيد الكرة. وهكذا دواليك.
مثال بسيط باستخدام جافاسكريبت لتوضيح الفكرة:
// Polling Example using JavaScript
// تخيل أن هذا الكود يعمل على سيرفر Node.js
const CHECK_INTERVAL = 5000; // 5 ثواني
setInterval(async () => {
try {
console.log("جاري التحقق من وجود تحديثات...");
const response = await fetch('https://api.supplier.com/product/123/status');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
// لنفترض أننا نخزن الحالة القديمة للمقارنة
if (data.stock !== oldStock) {
console.log(`تحديث جديد! المخزون تغير إلى: ${data.stock}`);
updateProductInOurDB(data); // نقوم بتحديث قاعدة بياناتنا
} else {
console.log("لا يوجد شيء جديد.");
}
} catch (error) {
console.error("حدث خطأ أثناء عملية الاستقصاء:", error);
}
}, CHECK_INTERVAL);
عيوب الـ Polling الكارثية
من المثال السابق، يمكن أن تبدو الأمور سهلة، ولكن على نطاق واسع، تظهر العيوب القاتلة:
- استنزاف الموارد (Resource Intensive): كل طلب يستهلك موارد من السيرفر والعميل (CPU, Memory, Bandwidth)، حتى لو لم يكن هناك أي تحديث. تخيل آلاف المنتجات وكل واحد منها يحتاج لـ Polling!
- التأخير الزمني (Latency): البيانات ليست فورية حقاً. إذا حدث تحديث بعد ثانية واحدة من آخر طلب، فلن تعرف به إلا بعد 4 ثوانٍ (في مثالنا). هذا التأخير يسمى “الكمون”.
- مشاكل التوسع (Scalability): كلما زاد عدد العملاء الذين يقومون بالـ Polling، زاد العبء على الخادم بشكل كبير، مما قد يؤدي إلى انهياره.
- طلبات فارغة لا طائل منها: كما ذكرت في قصتي، الغالبية العظمى من الطلبات تعود فارغة، وهذا هدر هائل وغير فعال. “زي اللي بروح مشوار عالفاضي وبصرف بنزين”.
الخطافات الشبكية (Webhooks): المنقذ الذي يطرق بابك
الآن لنتحدث عن الحل السحري: الـ Webhooks. الاسم قد يبدو غريباً “خطافات شبكية”، لكن الفكرة عبقرية في بساطتها. بدلاً من أن تقوم أنت بالسؤال بشكل مستمر، أنت تخبر الخدمة الأخرى: “يا صديقي، هذا هو عنواني (URL). إذا حدث شيء معين (Event)، أرجوك أرسل لي إشعاراً على هذا العنوان مع تفاصيل ما حدث (Payload)”.
ببساطة، الـ Webhooks تعكس منطق الـ API التقليدي. بدلاً من أن يقوم العميل بسحب (Pull) البيانات، يقوم الخادم بدفع (Push) البيانات إليه عند وقوع حدث معين. لهذا السبب يطلق عليها أحياناً “Reverse APIs”.
كيف تعمل الـ Webhooks؟
العملية تتم على خطوتين رئيسيتين:
- التسجيل: تقوم أنت (العميل) بتزويد الخدمة الأخرى (الخادم) بـ URL خاص بك. هذا الـ URL هو عبارة عن Endpoint على سيرفرك جاهز لاستقبال طلبات POST. تقوم أيضاً بتحديد الأحداث التي تهمك (مثلاً: `product.updated`, `order.created`).
- الإشعار: عندما يقع الحدث الذي اشتركت فيه داخل نظام الخادم (مثلاً، تغير سعر منتج)، يقوم الخادم تلقائياً بإرسال طلب HTTP POST إلى الـ URL الذي سجلته، ومعه “حمولة” (Payload) تحتوي على كل تفاصيل الحدث بصيغة JSON.
سيرفرك يستقبل هذا الطلب، يقرأ البيانات، ويقوم بالإجراء اللازم. لا يوجد انتظار، لا يوجد طلبات متكررة، فقط اتصال فعال عند الحاجة.
مثال بسيط على سيرفر Node.js/Express يستقبل Webhook:
// Webhook Endpoint Example (على السيرفر الخاص بنا)
const express = require('express');
const app = express();
// Middleware لتحليل الـ JSON القادم في جسم الطلب
app.use(express.json());
// هذا هو الـ URL الذي سنعطيه لنظام المورد
// e.g., https://our-store.com/webhooks/supplier-updates
app.post('/webhooks/supplier-updates', (req, res) => {
const eventPayload = req.body;
// من الجيد دائماً التحقق من مصدر الـ Webhook (عبر التوقيعات مثلاً)
// لكن للتبسيط، سنتجاوز هذه الخطوة هنا
console.log('تم استقبال Webhook جديد!', eventPayload);
// التحقق من نوع الحدث والتصرف بناءً عليه
if (eventPayload.event === 'product.stock.updated') {
const { productId, newStock } = eventPayload.data;
console.log(`تحديث مخزون المنتج ${productId} إلى ${newStock}`);
// هنا نكتب الكود لتحديث قاعدة بياناتنا
updateProductStockInDB(productId, newStock);
}
// يجب أن نرسل رداً ناجحاً (200 OK) بسرعة
// لإعلام الخادم أننا استلمنا الإشعار بنجاح
res.status(200).send('Received');
});
const PORT = 3000;
app.listen(PORT, () => {
console.log(`السيرفر يستمع للـ Webhooks على البورت ${PORT}`);
});
نصيحة من أبو عمر: عندما تبني Endpoint لاستقبال Webhook، تأكد من أن منطق المعالجة سريع جداً. لا تقم بعمليات معقدة أو طويلة داخل نفس الطلب. استلم البيانات، تحقق منها، خزنها في طابور مهام (Queue) للمعالجة لاحقاً، ثم أرسل رداً بـ `200 OK` فوراً. هذا يضمن أنك لن تتسبب في `timeout` للخدمة المرسلة.
نصائح من أبو عمر: متى نستخدم هذا وذاك؟
رغم أني أمدح الـ Webhooks وكأنها الحل لكل شيء، لكن لكل أداة مكانها وزمانها. البرمجة ليست أبيض وأسود.
استخدم الـ Polling عندما…
- الـ API لا يدعم Webhooks: أحياناً تكون مجبراً لا بطلاً. بعض الخدمات القديمة أو البسيطة لا توفر خيار الـ Webhooks.
- لا تحتاج إلى بيانات فورية: إذا كان تحديث البيانات كل ساعة أو كل يوم كافياً (مثل تقرير مبيعات يومي)، فالـ Polling باستخدام Cron Job هو حل بسيط ومناسب.
- حالة البيانات تتغير باستمرار وبشكل غير متوقع: في بعض الحالات النادرة جداً (مثل تتبع أسعار الأسهم لحظياً)، قد يكون هناك تقنيات أخرى مثل WebSockets أفضل، ولكن Polling قصير الأمد قد يكون خياراً مؤقتاً.
استخدم الـ Webhooks عندما…
- تحتاج إلى إشعارات شبه فورية (Near Real-time): هذا هو الاستخدام الأمثل. مثل إشعارات الدفع، رسائل الدردشة، تحديثات حالة الطلب، أنظمة CI/CD.
- تريد بناء نظام فعال وموفر للموارد: الـ Webhooks هي صديقة السيرفرات والميزانية.
- تريد أتمتة العمليات بين خدمات مختلفة: خدمات مثل Zapier و IFTTT مبنية بالكامل على مفهوم الـ Webhooks لربط آلاف التطبيقات معاً (عندما يحدث ‘X’ في تطبيق ‘أ’، قم بفعل ‘Y’ في تطبيق ‘ب’).
الخلاصة: لا تكن السائل الملِح، كن المستمع الذكي
الانتقال من عقلية الـ “Pull” (Polling) إلى عقلية الـ “Push” (Webhooks) هو نقلة نوعية في التفكير كمهندس برمجيات. إنه يعني الانتقال من الهدر وعدم الكفاءة إلى الدقة والفعالية. في قصتنا، بعد تطبيق الـ Webhooks، انخفض استهلاك سيرفراتنا بنسبة تزيد عن 80%، وأصبحت تحديثات المخزون والأسعار فورية، وتخلصنا من كابوس الطلبات الفاشلة والموارد الضائعة.
لذا في مشروعك القادم، قبل أن تكتب أول `setInterval`، اسأل نفسك: “هل أنا حقاً بحاجة للسؤال، أم يمكنني فقط أن أستمع؟”. الإجابة على هذا السؤال قد توفر عليك وعلى فريقك وعلى ميزانيتك الكثير من العناء. فكر بذكاء، وبرمج بكفاءة. بالتوفيق يا جماعة! 😉