أنظمتنا كانت تسأل ‘هل هناك جديد؟’ كل ثانية: كيف أنقذتنا ‘الخطافات الشبكية’ (Webhooks) من جحيم الاستقصاء المستمر (Polling)؟

يا جماعة الخير، السلام عليكم ورحمة الله. معكم أخوكم أبو عمر.

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

في البداية، الحل اللي كان “واضح” و”سهل” هو أن نجعل نظامنا يسأل الخدمة الخارجية كل ثانية: “خلصتي شغل؟”، “طيب هسا خلصتي؟”، “طيب شو صار؟ في إشي جديد؟”. بالانجليزي، هذا الأسلوب اسمه Polling أو الاستقصاء المستمر. في أول أسبوع، الأمور كانت تمام. لكن لما زاد الضغط على النظام، وزاد عدد العمليات، بدأت المأساة. الخوادم صارت “بتولّع”، استهلاك المعالج (CPU) في السماء، وفاتورة الخدمات السحابية صارت تحرق القلب حرق. كنا كمن أرسل طفلاً إلى دكان البقالة، وبدلاً من أن ينتظر عودته، يلحقه كل خطوة ويسأله: “وصلت؟ طب هسا وصلت؟”.

في أحد الأيام، وأنا أشرب فنجان القهوة السادة وأتأمل لوحة مراقبة أداء الأنظمة (Dashboard) التي كانت كلها باللون الأحمر، قلت للفريق: “يا زلمة، شو هالحكي؟ لازم يكون في طريقة أحسن! طريقة نخلي فيها الخدمة الخارجية هي اللي تحكيلنا لما تخلص، مش إحنا اللي نضل نلاحقها!”. وهنا بدأت رحلتنا مع المنقذ: الـ Webhooks.

ما هو الاستقصاء المستمر (Polling)؟ أو “مش كل ساعة تضل ترن عليّ!”

لنبسط المفهوم، تخيل أنك تنتظر طرداً مهماً. باستخدام طريقة الـ Polling، أنت تذهب إلى مكتب البريد كل 5 دقائق لتسأل الموظف: “هل وصل طردي؟”. تعود إلى المنزل، وبعد 5 دقائق، ترجع مرة أخرى وتسأل نفس السؤال. معظم إجابات الموظف ستكون “لا، لم يصل شيء بعد”. أنت أهدرت وقتك ومجهودك، وأزعجت الموظف الذي كان بإمكانه خدمة عملاء آخرين.

تقنياً، الـ Polling هو عندما يقوم تطبيق العميل (Client) بإرسال طلبات HTTP بشكل متكرر إلى الخادم (Server) للتحقق من وجود بيانات جديدة أو تحديثات.

كيف يعمل الـ Polling؟

الآلية بسيطة ومباشرة بشكل يبعث على الشك:

  1. العميل يرسل طلب GET إلى الخادم، سائلاً: “هل هناك أي تحديثات؟”
  2. الخادم يفحص حالته، ثم يجيب. في 99% من الحالات، الإجابة تكون: “لا، لا يوجد شيء جديد.”
  3. العميل ينتظر فترة زمنية محددة (مثلاً، ثانية واحدة).
  4. العميل يعود إلى الخطوة 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؟

العملية أكثر أناقة وفعالية وتتكون من الخطوات التالية:

  1. التسجيل (Registration): أنت (العميل) تزود الخدمة (الخادم) بعنوان URL خاص بك. هذا الـ URL يسمى “Webhook Endpoint”. وتقول للخدمة: “يا خدمة، عندما يقع الحدث X (مثلاً، اكتمال عملية دفع)، أرسلي لي إشعاراً على هذا الرابط”.
  2. الحدث (The Event): يقع الحدث المنتظر على الخادم (مثلاً، مستخدم جديد سجل، أو تم رفع ملف بنجاح).
  3. الإشعار (The Notification): يقوم الخادم فوراً بتكوين طلب HTTP (عادةً من نوع POST) يحتوي على معلومات حول الحدث (تسمى الـ Payload)، ويرسله إلى الـ URL الذي سجلته في الخطوة الأولى.
  4. الاستلام والمعالجة (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) هو أكثر من مجرد تغيير تقني؛ إنه تغيير في العقلية. هو الانتقال من نظام “لحوح” ومستهلك للموارد يسأل باستمرار “هل هناك جديد؟”، إلى نظام “ذكي” وفعال يقول للآخرين “عندما يكون هناك جديد، أخبرني!”.

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

أبو عمر

سجل دخولك لعمل نقاش تفاعلي

كافة المحادثات خاصة ولا يتم عرضها على الموقع نهائياً

آراء من النقاشات

لا توجد آراء منشورة بعد. كن أول من يشارك رأيه!

آخر المدونات

ذكاء اصطناعي

بحثنا كان يعثر على الكلمات، لا على النوايا: كيف أنقذتنا قواعد بيانات المتجهات من جحيم البحث الدلالي الأعمى؟

أشارككم قصة من قلب المعركة البرمجية، يوم كان نظام البحث لدينا أصمًا وأعمى، لا يفهم سوى تطابق الكلمات. سنغوص في عالم قواعد بيانات المتجهات (Vector...

14 أبريل، 2026 قراءة المزيد
خوارزميات

قاعدة بياناتنا كانت تجيب على ‘هل هذا موجود؟’ ببطء قاتل: كيف أنقذنا ‘مرشح بلوم’ (Bloom Filter) من جحيم الاستعلامات المكلفة؟

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

14 أبريل، 2026 قراءة المزيد
تجربة المستخدم والابداع البصري

موقعنا كان يستبعد الملايين بصمت: كيف أنقذتنا ‘معايير الوصولية’ (Accessibility) من جحيم التصميم الإقصائي؟

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

14 أبريل، 2026 قراءة المزيد
برمجة وقواعد بيانات

استعلاماتنا كانت تزحف: كيف أنقذتنا ‘فهارس قاعدة البيانات’ من جحيم فحص الجداول الكاملة؟

أشارككم قصة حقيقية من قلب المعركة البرمجية، حين كاد تطبيقنا أن ينهار بسبب بطء الاستعلامات. اكتشفوا معنا كيف كانت "فهارس قاعدة البيانات" هي طوق النجاة...

14 أبريل، 2026 قراءة المزيد
الحوسبة السحابية

تطبيقنا كان رهينة منطقة جغرافية واحدة: كيف أنقذتنا استراتيجية ‘متعددة المناطق’ (Multi-Region) من جحيم الانقطاع الكامل؟

أشارككم قصة حقيقية عن يوم توقف فيه تطبيقنا بالكامل بسبب انقطاع في منطقة سحابية واحدة، وكيف كانت استراتيجية "متعددة المناطق" (Multi-Region) هي طوق النجاة. سأشرح...

14 أبريل، 2026 قراءة المزيد
التوظيف وبناء الهوية التقنية

حسابي في GitHub كان مقبرة صامتة: كيف أنقذني ‘ملف التعريف المميّز’ من جحيم التجاهل؟

كنتُ أرى حسابي في GitHub كمقبرة لمشاريعي، مجرد أرشيف لا يلتفت إليه أحد. في هذه المقالة، سأشارككم قصتي، يا جماعة، كيف حوّلت هذا المستودع الصامت...

14 أبريل، 2026 قراءة المزيد
التوسع والأداء العالي والأحمال

عطل خدمة واحدة كاد ينسف النظام: كيف أنقذنا نمط “قاطع الدائرة” من جحيم الأعطال المتتالية؟

أشارككم قصة حقيقية من قلب المعركة التقنية، يوم كاد عطل في خدمة دفع صغيرة أن ينهار معه نظامنا بأكمله. سنغوص في تفاصيل نمط "قاطع الدائرة"...

14 أبريل، 2026 قراءة المزيد
البودكاست