يا جماعة الخير، السلام عليكم ورحمة الله. معكم أخوكم أبو عمر.
خليني أحكيلكم قصة صارت معي قبل كم سنة، قصة بتجسد معنى “وجع الراس” التقني. كنا في الشركة نبني نظاماً معقداً يعتمد على خدمة خارجية لمعالجة بعض البيانات المهمة. الفكرة كانت بسيطة: نظامنا يرسل بيانات، والخدمة الخارجية تعالجها، وعندما تنتهي من المعالجة، يجب على نظامنا أن يعرف بذلك ليقوم بالخطوة التالية.
في البداية، الحل اللي كان “واضح” و”سهل” هو أن نجعل نظامنا يسأل الخدمة الخارجية كل ثانية: “خلصتي شغل؟”، “طيب هسا خلصتي؟”، “طيب شو صار؟ في إشي جديد؟”. بالانجليزي، هذا الأسلوب اسمه Polling أو الاستقصاء المستمر. في أول أسبوع، الأمور كانت تمام. لكن لما زاد الضغط على النظام، وزاد عدد العمليات، بدأت المأساة. الخوادم صارت “بتولّع”، استهلاك المعالج (CPU) في السماء، وفاتورة الخدمات السحابية صارت تحرق القلب حرق. كنا كمن أرسل طفلاً إلى دكان البقالة، وبدلاً من أن ينتظر عودته، يلحقه كل خطوة ويسأله: “وصلت؟ طب هسا وصلت؟”.
في أحد الأيام، وأنا أشرب فنجان القهوة السادة وأتأمل لوحة مراقبة أداء الأنظمة (Dashboard) التي كانت كلها باللون الأحمر، قلت للفريق: “يا زلمة، شو هالحكي؟ لازم يكون في طريقة أحسن! طريقة نخلي فيها الخدمة الخارجية هي اللي تحكيلنا لما تخلص، مش إحنا اللي نضل نلاحقها!”. وهنا بدأت رحلتنا مع المنقذ: الـ Webhooks.
ما هو الاستقصاء المستمر (Polling)؟ أو “مش كل ساعة تضل ترن عليّ!”
لنبسط المفهوم، تخيل أنك تنتظر طرداً مهماً. باستخدام طريقة الـ Polling، أنت تذهب إلى مكتب البريد كل 5 دقائق لتسأل الموظف: “هل وصل طردي؟”. تعود إلى المنزل، وبعد 5 دقائق، ترجع مرة أخرى وتسأل نفس السؤال. معظم إجابات الموظف ستكون “لا، لم يصل شيء بعد”. أنت أهدرت وقتك ومجهودك، وأزعجت الموظف الذي كان بإمكانه خدمة عملاء آخرين.
تقنياً، الـ Polling هو عندما يقوم تطبيق العميل (Client) بإرسال طلبات HTTP بشكل متكرر إلى الخادم (Server) للتحقق من وجود بيانات جديدة أو تحديثات.
كيف يعمل الـ Polling؟
الآلية بسيطة ومباشرة بشكل يبعث على الشك:
- العميل يرسل طلب
GETإلى الخادم، سائلاً: “هل هناك أي تحديثات؟” - الخادم يفحص حالته، ثم يجيب. في 99% من الحالات، الإجابة تكون: “لا، لا يوجد شيء جديد.”
- العميل ينتظر فترة زمنية محددة (مثلاً، ثانية واحدة).
- العميل يعود إلى الخطوة 1، ويكرر العملية إلى ما لا نهاية.
مثال بسيط باستخدام JavaScript لتوضيح الفكرة:
// Polling a 'status' endpoint every 2 seconds
setInterval(async () => {
console.log("Asking the server: Is there anything new?");
try {
const response = await fetch('https://api.example.com/status');
const data = await response.json();
if (data.status === 'completed') {
console.log("Finally! The task is complete.");
// Stop polling and do the next step
// clearInterval(this); // This line needs proper context to work
} else {
console.log("Server says: Not yet...");
}
} catch (error) {
console.error("Error during polling:", error);
}
}, 2000); // 2000 milliseconds = 2 seconds
مساوئ الـ Polling: جحيم الهدر
هذه الطريقة، رغم بساطتها، لها عيوب قاتلة على نطاق واسع:
- استهلاك الموارد: كل طلب هو عبء على الشبكة، وعلى معالج الخادم، وعلى ذاكرة العميل. آلاف العملاء يقومون بالـ Polling كل ثانية؟ هذه وصفة لكارثة أداء.
- التأخير (Latency): أنت لا تحصل على التحديث في لحظة حدوثه، بل في لحظة سؤالك التالي. لو كان الفاصل الزمني للاستقصاء 10 ثوانٍ، وحدث التحديث في الثانية الأولى، فأنت متأخر 9 ثوانٍ عن الواقع.
- مشاكل في التوسع (Scalability): كلما زاد عدد العملاء، زادت الطلبات بشكل خطي، مما يضع ضغطاً هائلاً على البنية التحتية للخادم ويجعل عملية التوسع مكلفة ومعقدة. “السيرفر راح يفرط منك”.
الحل السحري: الخطافات الشبكية (Webhooks) أو “لما يصير إشي، خبّرني!”
بالعودة إلى مثال طرد البريد، تخيل الآن أنك أعطيت ساعي البريد رقم هاتفك وقلت له: “عندما يصل طردي، اتصل بي فوراً”. الآن يمكنك العودة إلى منزلك وممارسة حياتك بشكل طبيعي. لن تتصل بك خدمة البريد إلا عندما يكون هناك خبر حقيقي: “طردك وصل!”.
هذا بالضبط هو مبدأ عمل الـ Webhooks. إنها آلية تتيح لتطبيق ما أن يرسل بيانات إلى تطبيق آخر في الوقت الفعلي (real-time) بمجرد وقوع حدث معين. أحياناً يطلق عليها اسم “واجهات برمجة التطبيقات العكسية” (Reverse APIs) لأن الخادم هو من يبادر بالاتصال بالعميل، وليس العكس.
كيف تعمل الـ Webhooks؟
العملية أكثر أناقة وفعالية وتتكون من الخطوات التالية:
- التسجيل (Registration): أنت (العميل) تزود الخدمة (الخادم) بعنوان URL خاص بك. هذا الـ URL يسمى “Webhook Endpoint”. وتقول للخدمة: “يا خدمة، عندما يقع الحدث X (مثلاً، اكتمال عملية دفع)، أرسلي لي إشعاراً على هذا الرابط”.
- الحدث (The Event): يقع الحدث المنتظر على الخادم (مثلاً، مستخدم جديد سجل، أو تم رفع ملف بنجاح).
- الإشعار (The Notification): يقوم الخادم فوراً بتكوين طلب HTTP (عادةً من نوع
POST) يحتوي على معلومات حول الحدث (تسمى الـ Payload)، ويرسله إلى الـ URL الذي سجلته في الخطوة الأولى. - الاستلام والمعالجة (Receiving & Processing): نظامك، الذي يكون “يستمع” على هذا الـ URL، يستقبل الطلب، يقرأ البيانات، وينفذ الإجراء المطلوب (مثل تحديث قاعدة البيانات، إرسال بريد إلكتروني للمستخدم، الخ).
هنا مثال بسيط جداً لخادم يستقبل Webhook باستخدام Node.js و Express:
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('/webhook-receiver', (req, res) => {
console.log('Webhook received!');
// The 'body' contains the payload from the sending service
const payload = req.body;
console.log('Payload:', JSON.stringify(payload, null, 2));
// Example: Check for a specific event type from a service like Stripe or GitHub
const eventType = req.headers['x-github-event'] || payload.type; // Header might vary
if (eventType === 'checkout.session.completed') {
console.log('Payment was successful! Updating user account...');
// Add logic here to handle the successful payment
}
// IMPORTANT: Respond immediately with a 200 OK to let the sender know
// you received the webhook. Don't do heavy processing before this.
res.status(200).send('Webhook received successfully.');
});
app.listen(PORT, () => {
console.log(`Server is running and listening for webhooks on http://localhost:${PORT}/webhook-receiver`);
});
Polling vs. Webhooks: متى نستخدم كل منهما؟
بعد كل هذا المديح للـ Webhooks، هل يعني هذا أن الـ Polling سيء ويجب أن ندفنه إلى الأبد؟ ليس تماماً. لكل أداة مكانها وزمانها.
نصيحة من أبو عمر: في هندسة البرمجيات، نادراً ما يوجد حل “أفضل” بشكل مطلق. دائماً يوجد حل “أنسب” للسياق الحالي.
استخدم الـ Polling عندما…
- الخدمة التي تتعامل معها لا تدعم الـ Webhooks. أحياناً “ما في بالإيد حيلة” وتكون مجبراً على استخدام هذه الطريقة.
- البيانات تتغير باستمرار وبشكل متوقع (مثل أسعار الأسهم كل ثانية)، والخدمة لا تعتبر كل تغيير “حدثاً” يستدعي إرسال Webhook.
- فاصل الاستقصاء طويل جداً (مثلاً، التحقق من تحديث جديد للبرنامج مرة كل يوم)، وتكلفة الطلب شبه معدومة.
استخدم الـ Webhooks عندما…
- تحتاج إلى تحديثات فورية أو شبه فورية.
- الحدث غير متوقع الحدوث (مثل استلام بريد إلكتروني، إتمام عملية شراء، تعليق مستخدم على منشور).
- تريد بناء نظام فعال من حيث الموارد، قابل للتوسع، وبتكاليف تشغيل أقل.
- الخدمة التي تتكامل معها تدعمها (وهذا هو الحال مع معظم الخدمات الحديثة مثل Stripe, GitHub, Slack, Twilio, etc).
نصائح من خبرة أبو عمر
العمل مع الـ Webhooks ممتع، لكن هناك بعض الأمور التي يجب الانتباه إليها لتجنب المشاكل:
1. أمّن الـ Webhooks تبعك! (Security)
الـ Webhook endpoint الخاص بك هو عبارة عن URL عام على الإنترنت. أي شخص يعرفه يمكنه إرسال طلبات إليه. “مش كل مين دق الباب تفتحله!”. لذلك، يجب أن تتأكد من أن الطلبات التي تصلك هي من المصدر الموثوق. معظم الخدمات المحترمة تستخدم آلية توقيع الطلبات (Signature Verification):
- تعطيك الخدمة “سراً” (Secret Key).
- عندما ترسل لك Webhook، تقوم بتوقيع الـ Payload باستخدام هذا السر، وتضع التوقيع في أحد الـ Headers (مثل
X-Hub-Signature). - عندما تستقبل الطلب، تقوم أنت بنفس عملية التوقيع على الـ Payload باستخدام نفس السر، وتقارن نتيجتك مع التوقيع الموجود في الـ Header. إذا تطابقا، فالطلب أصلي. إذا لم يتطابقا، تجاهل الطلب فوراً.
2. تعامل مع الأخطاء والفشل بذكاء
ماذا لو كان خادمك متوقفاً عن العمل للحظة التي أُرسل فيها الـ Webhook؟ معظم الخدمات لديها سياسة إعادة محاولة (Retry Policy). ولكن لتعمل هذه السياسة بشكل صحيح، يجب على خادمك أن يكون “مواطناً صالحاً” في عالم الـ Web:
- أجب بسرعة: بمجرد استلام الـ Webhook والتحقق من صحته، أرسل استجابة
200 OKفوراً. هذا يخبر المرسل أنك استلمت الإشعار بنجاح. - اعمل لاحقاً: لا تقم بالعمليات الثقيلة (مثل استدعاءات API أخرى، تحديثات معقدة لقاعدة البيانات) قبل إرسال الـ
200 OK. هذا قد يؤدي إلى انتهاء مهلة الطلب (Timeout) ويعتقد المرسل أنك فشلت في الاستلام. الحل الأفضل هو وضع بيانات الـ Webhook في طابور مهام (Job Queue) مثل RabbitMQ أو Redis ومعالجتها في الخلفية (Asynchronously).
3. استخدم أدوات لتسهيل الاختبار
أثناء التطوير، يكون خادمك يعمل على جهازك المحلي (localhost)، وهو غير متاح على الإنترنت. فكيف ستستقبل الـ Webhooks من خدمات مثل GitHub؟ هنا تأتي أدوات “فك الأزمات” مثل ngrok. هذه الأداة البسيطة تنشئ نفقاً آمناً بين الإنترنت العام وجهازك المحلي، وتعطيك URL عام يمكنك استخدامه كـ Webhook endpoint أثناء التطوير والاختبار. إنها أداة لا غنى عنها. ✅
الخلاصة: من السؤال إلى الاستماع
الانتقال من الاستقصاء المستمر (Polling) إلى الخطافات الشبكية (Webhooks) هو أكثر من مجرد تغيير تقني؛ إنه تغيير في العقلية. هو الانتقال من نظام “لحوح” ومستهلك للموارد يسأل باستمرار “هل هناك جديد؟”، إلى نظام “ذكي” وفعال يقول للآخرين “عندما يكون هناك جديد، أخبرني!”.
في قصتنا، هذا التغيير البسيط أنقذ خوادمنا من الانهيار، وخفض فواتيرنا بشكل ملحوظ، وحوّل نظامنا من نظام بطيء ومتأخر إلى نظام يستجيب للأحداث فور وقوعها. ففي المرة القادمة التي تبني فيها تكاملاً بين نظامين، اسأل نفسك: هل أنا بحاجة حقاً لأن أظل أسأل، أم يمكنني ببساطة أن أستمع؟ الإجابة قد توفر عليك الكثير من الوقت، والمال، ووجع الرأس. 🚀