يا جماعة الخير، السلام عليكم ورحمة الله. معكم أخوكم أبو عمر.
قبل كم سنة، كنت شغال مع فريق على نظام متجر إلكتروني كبير. كان واحد من التحديات الرئيسية هو مزامنة حالة الطلبات مع نظام إدارة المخزون وشحن البضائع، وهو نظام تابع لشركة ثانية (Third-party). يعني لما الزبون يشتري غرض، لازم نبعث خبر لشركة الشحن، ولما شركة الشحن تجهّز الطلبية أو تشحنها، لازم نعرف فوراً عشان نحدّث حالة الطلب عند الزبون ونبعتله إشعار.
في البداية، شو عملنا؟ الحل السريع والسهل اللي خطر ببالنا كان الـ “Polling”. كتبنا سكربت بسيط، كل ثانية يروح يسأل الـ API تبع شركة الشحن: “يا جماعة، في إشي جديد بخصوص الطلب رقم 123؟”، “طيب والطلب 124؟”، “طيب و125؟”. وهكذا دواليك لكل الطلبات المفتوحة. في أول يومين ثلاثة، كانت الأمور تمام والوضع “عال العال”.
لكن مع زيادة الطلبات، بدأت المصايب تظهر. الخادم (السيرفر) تبعنا صار زي فرن الخبز من كثر الضغط، استهلاك المعالج والذاكرة وصل للسما. وفوق كل هاد، شركة الشحن بعتتلنا إيميل محترم بيقول: “يا عمي خفّوا علينا شوي، عملتوا عنا مليون طلب API بيوم واحد! إذا بتضلوا هيك رح نعمللكم Block”. وقتها حسيت الدنيا ولّعت فوق راسنا. كنا في جحيم حقيقي اسمه “الاستطلاع المستمر”، وكنا بنحرق مواردنا وموارد غيرنا على الفاضي.
هنا كانت نقطة التحول. بعد بحث ونقاش، قررنا نتبنى الحل الأمثل والأكثر احترافية: خطافات الويب (Webhooks). ومن يومها، تغير كل شيء. خلوني أحكيلكم القصة بالتفصيل التقني، وكيف ممكن تستفيدوا من تجربتنا.
ما هو الاستطلاع المستمر (Polling)؟ أو “طريقة دق الباب كل شوي”
ببساطة شديدة، الـ Polling هو إنك كـ “عميل” (Client)، تضل تسأل الـ “خادم” (Server) بشكل متكرر إذا كان في أي تحديثات جديدة. تخيل حالك مستني صاحبك يجهز عشان تطلعوا، فبتروح كل دقيقة تدق عليه الباب وتسأله: “خلصت؟”. في معظم المرات، رح يكون جوابه “لسا”، وهيك بتكون ضيعت وقتك ومجهودك في المشوار لعنده.
كيف يعمل الـ Polling؟
الآلية بسيطة جداً وتتلخص في حلقة لا نهائية:
- العميل يرسل طلب HTTP (عادةً GET) للخادم: “هل هناك أي بيانات جديدة؟”
- الخادم يفحص قاعدة بياناته أو حالته الداخلية ويرد. إما ببيانات جديدة، أو برد فارغ مثل
{"updates": false}. - العميل ينتظر فترة زمنية محددة (مثلاً، ثانية واحدة أو 5 ثوانٍ).
- يعود العميل إلى الخطوة 1.
الكود يتحدث: مثال بسيط على الـ Polling بـ JavaScript
هذا مثال بسيط يوضح الفكرة باستخدام JavaScript في المتصفح. الكود يحاول جلب تحديثات كل 3 ثوانٍ.
// The ID of the order we are tracking
const orderId = 'xyz-123';
// Function to check for updates
async function checkOrderStatus() {
try {
const response = await fetch(`https://api.example.com/orders/${orderId}/status`);
if (!response.ok) {
console.error('Network response was not ok');
return;
}
const data = await response.json();
// If there is a new status, update the UI
if (data.new_status) {
console.log('New status received:', data.status);
// updateUI(data.status);
} else {
console.log('No new updates yet...');
}
} catch (error) {
console.error('Failed to fetch status:', error);
}
}
// Poll every 3 seconds
setInterval(checkOrderStatus, 3000);
الكود واضح، لكن تخيل آلاف العملاء يقومون بهذا الإجراء في نفس الوقت. إنها وصفة لكارثة في الأداء.
جحيم الـ Polling: لماذا هو فكرة سيئة في معظم الأحيان؟
تجربتنا المريرة مع الـ Polling لخصت لنا عيوبه القاتلة:
- استهلاك فظيع للموارد: كل طلب استطلاع يستهلك موارد الشبكة، المعالج، والذاكرة على الخادم والعميل، حتى لو لم يكن هناك أي تحديث. 99% من الطلبات كانت تعود فارغة، وهذا هدر محض.
- التأخير الحتمي (Latency): التحديثات ليست فورية. إذا كان الفاصل الزمني للاستطلاع 5 ثوانٍ، فقد ينتظر المستخدم 4.9 ثانية كاملة بعد حدوث التغيير الفعلي قبل أن يراه.
- مشاكل التوسع (Scalability): كلما زاد عدد العملاء، زاد الحمل على الخادم بشكل خطي. إذا كان لديك مليون مستخدم، فهذا يعني ملايين الطلبات كل بضع ثوانٍ. هذا لا يمكن أن يستمر.
- قيود الاستخدام (Rate Limiting): معظم واجهات برمجة التطبيقات (APIs) تفرض حداً على عدد الطلبات التي يمكنك إجراؤها في الدقيقة أو الساعة. مع الـ Polling، من السهل جداً تجاوز هذا الحد والتعرض للحظر، زي ما كان رح يصير معنا.
المنقذ: خطافات الويب (Webhooks) أو “لما تجهز، رن عليّ”
الـ Webhook يقلب المعادلة رأساً على عقب. بدلاً من أن يسأل العميل الخادم باستمرار، يقوم الخادم بإخبار العميل عند وقوع حدث معين. نرجع لمثال صاحبك: بدل ما تضل تدق الباب عليه، بتعطيه رقم تلفونك وبتقوله: “لما تجهز، ابعثلي رسالة أو رن عليّ”.
بالمصطلح التقني، الـ Webhook هو “رد نداء HTTP” (HTTP callback) أو “HTTP Push API”. أنت تقوم بتزويد الخدمة (مثل بوابة الدفع، أو نظام الشحن) بعنوان URL خاص بتطبيقك. وعندما يحدث شيء يهمك (مثل إتمام عملية دفع، أو تغيير حالة الشحنة)، تقوم تلك الخدمة بإرسال طلب HTTP POST إلى عنوانك، محمّلاً بالبيانات ذات الصلة.
كيف تعمل الـ Webhooks؟
- الإعداد (مرة واحدة): أنت (العميل) تدخل على لوحة تحكم الخدمة (الخادم) وتسجل عنوان URL خاص بك، يسمى “Webhook Endpoint”. هذا الـ Endpoint هو جزء من الكود تبعك ومستعد لاستقبال البيانات.
- وقوع الحدث: يحدث شيء على الخادم (مثلاً، تم شحن طلبية).
- الإشعار: الخادم يقوم فوراً بإنشاء طلب HTTP POST، يضع فيه تفاصيل الحدث (مثلاً، بيانات الطلب وحالته الجديدة) في جسم الطلب (Body) بصيغة JSON، ويرسله إلى الـ URL الذي سجلته.
- المعالجة: تطبيقك يستقبل هذا الطلب، يتأكد من صحته، ثم يقوم بالإجراء اللازم (تحديث قاعدة البيانات، إرسال إيميل للزبون، إلخ).
الكود يتحدث: إعداد نقطة نهاية (Endpoint) لاستقبال Webhook
هذا مثال بسيط باستخدام Node.js و Express لإنشاء خادم يستمع لطلبات الـ Webhooks القادمة.
const express = require('express');
const app = express();
// Middleware to parse JSON bodies. This is crucial!
app.use(express.json());
const PORT = 3000;
// This is our Webhook Endpoint
app.post('/webhooks/shipping-updates', (req, res) => {
console.log('Webhook received!');
// The data sent by the third-party service is in the request body
const payload = req.body;
console.log('Payload:', payload);
// Example payload: { orderId: 'xyz-123', newStatus: 'shipped', trackingNumber: '...' }
const { orderId, newStatus } = payload;
// Now, do something with the data
// e.g., update your database, notify the user, etc.
// updateOrderStatusInDB(orderId, newStatus);
console.log(`Order ${orderId} status updated to ${newStatus}`);
// It's important to send a 200 OK response back quickly
// to let the sender know you've received the webhook successfully.
res.status(200).send('Webhook received');
});
app.listen(PORT, () => {
console.log(`Server listening for webhooks on port ${PORT}`);
});
نصيحة من أبو عمر: تأمين الـ Webhooks
يا جماعة، انتبهوا لنقطة مهمة جداً. الـ Endpoint تبع الـ Webhook هو عبارة عن URL عام على الإنترنت. أي حدا بيعرفهبيقدر يبعتلك عليه طلبات مزيفة. لهذا السبب، يجب تأمينه. الطريقة الأكثر شيوعاً هي “التحقق من التوقيع” (Signature Verification).
الفكرة كالتالي: عند إعداد الـ Webhook، تقوم الخدمة بإنشاء “سر مشترك” (Secret) بينك وبينها. عند إرسال أي Webhook، تقوم الخدمة بحساب “تجزئة” (Hash) للبيانات المرسلة (الـ payload) باستخدام هذا السر، وترسل لك نتيجة الـ Hash في هيدر خاص (مثلاً
X-Hub-Signature-256).
مهمتك أنت في الكود تبعك هي أن تقوم بنفس العملية: تستقبل الطلب، تأخذ الـ payload والـ Secret، تحسب الـ Hash بنفسك، وتقارنه مع الـ Hash اللي وصلك في الهيدر. إذا تطابقوا، فالطلب حقيقي. إذا لم يتطابقوا، فهذا طلب مزيف ويجب تجاهله.
مقارنة وجهاً لوجه: Polling vs. Webhooks
| المعيار | الاستطلاع المستمر (Polling) | خطافات الويب (Webhooks) |
|---|---|---|
| الكفاءة | منخفضة جداً، معظم الطلبات تكون هدر للموارد. | عالية جداً، لا يتم إرسال طلبات إلا عند وجود تحديث فعلي. |
| الفورية (Real-time) | يوجد تأخير يعتمد على الفاصل الزمني للاستطلاع. | فوري تقريباً، يتم الإشعار لحظة وقوع الحدث. |
| بنية الاتصال | العميل يبدأ الاتصال (Pull). | الخادم يبدأ الاتصال (Push). |
| التعقيد في الإعداد | بسيط جداً في البداية. | أكثر تعقيداً، يتطلب نقطة نهاية عامة (Public Endpoint) وتأمين. |
| قابلية التوسع | ضعيفة جداً. | ممتازة. |
نصائح عملية من مطبخ أبو عمر 🍳
بعد سنوات من التعامل مع الـ Webhooks، تعلمت بعض الدروس اللي بحب أشارككم فيها:
- اجعل معالج الـ Webhook سريعاً جداً: لا تقم بعمليات طويلة أو معقدة مباشرة عند استقبال الـ Webhook. مهمة الـ Endpoint هي استقبال الطلب، التحقق من صحته، ثم تمرير المهمة لعملية أخرى في الخلفية (Background Job). أفضل ممارسة هي وضع بيانات الـ Webhook في طابور (Message Queue) مثل RabbitMQ أو AWS SQS، ثم إرجاع استجابة
200 OKفوراً. هذا يمنع حدوث Timeouts من جهة المرسل. - كن مستعداً لإعادة الإرسال: أحياناً قد يكون الخادم تبعك معطلاً أو مشغولاً عند وصول الـ Webhook. الخدمات المحترمة تعيد إرسال الـ Webhook عدة مرات (Retry Mechanism). هذا يعني أن الكود تبعك يجب أن يكون “Idempotent”، أي أن معالجة نفس الحدث مرتين أو ثلاث لا تسبب مشكلة (مثلاً، لا ترسل للزبون إيميل “تم شحن الطلب” مرتين). يمكنك تحقيق ذلك عن طريق التحقق من معرف الحدث (Event ID) قبل معالجته.
- استخدم أدوات للاختبار المحلي: أثناء التطوير، يكون الخادم المحلي (localhost) الخاص بك غير متاح على الإنترنت. كيف ستستقبل الـ Webhooks؟ استخدم أدوات مثل ngrok التي تنشئ نفقاً آمناً من الإنترنت إلى جهازك المحلي. إنها أداة لا غنى عنها.
- التسجيل والمراقبة (Logging & Monitoring): سجل كل طلب Webhook يصلك (مع إخفاء البيانات الحساسة طبعاً). هذا سيساعدك بشكل لا يصدق في تصحيح الأخطاء عندما تسوء الأمور. “ليش ما تحدثت حالة الطلب؟”، الجواب غالباً ما يكون في سجلات الـ Webhooks.
الخلاصة: متى تستخدم هذا أو ذاك؟ 🤔
الخلاصة بسيطة ومباشرة:
👈 استخدم الـ Polling (بحذر شديد): عندما تكون مضطراً، أي عندما لا تدعم الخدمة التي تتعامل معها الـ Webhooks، أو عندما لا تحتاج إطلاقاً لتحديثات فورية ومعدل التغيير منخفض جداً (مثلاً، التحقق من الطقس مرة كل ساعة). اعتبره دائماً حلاً مؤقتاً أو الخيار الأخير.
🚀 استخدم الـ Webhooks (كلما أمكن): إنها الخيار الأمثل للاتصالات الفورية بين الخوادم، والتطبيقات التي تعتمد على الأحداث (Event-Driven Architecture)، وأنظمة الإشعارات، وتكامل الخدمات. إنها الطريقة الحديثة والفعالة لبناء أنظمة متجاوبة وقابلة للتوسع.
في عالم البرمجة، الكفاءة ليست فقط كتابة كود يعمل، بل كتابة كود ذكي يحترم الموارد والوقت. والـ Webhooks هي واحدة من أذكى الأدوات في جعبتنا. فاستخدموها بحكمة، وخليكم مبدعين! 😉