Webhooks vs Polling: كيف أنقذت ‘خطافات الويب’ تطبيقاتنا من جحيم الاستعلام الدوري؟

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

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

شو عملنا؟ برمجنا سكربت بسيط، “عامل مجتهد” إذا صح التعبير، وظيفته كل 10 ثواني يروح يسأل الـ API تبع المورّد: “يا عمي، في إشي جديد؟”، “تغيّر إشي؟”، “أمانة صار إشي؟”. في البداية، الأمور كانت تمام والوضع “عال العال”. لكن مع زيادة عدد المنتجات والمورّدين، تحوّل هذا العامل المجتهد لوحش بيستهلك موارد السيرفر بشكل مجنون. السيرفر صار “يصيح” من كثرة الطلبات، و 99% من هاي الطلبات كانت بترجع بجواب واحد: “لا، ما في إشي جديد”.

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

إلى أن جاء الفرج على هيئة مصطلح غريب وقتها: الـ Webhooks. وهنا بدأت القصة الحقيقية، قصة الانتقال من السؤال المستمر إلى الاستماع الذكي.

جحيم الاستعلام الدوري (Polling): الطريقة التقليدية المجهدة

قبل ما نغوص في الحل، خلينا نفصّل أكتر شو هو الـ Polling وليش هو متعب ومكلف. تخيل معي السيناريو اللي حكيته: تطبيقك (العميل) بحاجة لمعلومات من تطبيق آخر (السيرفر).

الـ Polling ببساطة: هو أن يقوم تطبيقك بإرسال طلب HTTP (عادةً GET) بشكل متكرر على فاصل زمني ثابت إلى سيرفر آخر ليسأله عن أي تحديثات جديدة.

هذا الأسلوب، ورغم بساطته، إلا أن له عيوب قاتلة في كثير من السيناريوهات:

  • استهلاك هائل للموارد: كل طلب استعلام يستهلك موارد من طرفك (CPU, Memory, Network) ومن طرف السيرفر المُستقبِل. معظم هذه الطلبات تكون “فاضية” ولا تحمل أي جديد، وهذا هدر حقيقي.
  • تأخير في الحصول على البيانات: البيانات ليست فورية. إذا كان الفاصل الزمني للاستعلام دقيقة واحدة، فقد تنتظر 59 ثانية كاملة قبل أن تعرف بحدوث تغيير مهم. تقليل الفاصل الزمني يزيد من استهلاك الموارد، فهي معادلة خاسرة.
  • مشاكل في قابلية التوسع (Scalability): كلما زاد عدد العملاء الذين يقومون بالـ Polling، زاد العبء على السيرفر بشكل كبير، مما قد يؤدي إلى انهياره.
  • قيود واجهة برمجة التطبيقات (API Rate Limiting): معظم الخدمات تفرض حداً أقصى لعدد الطلبات التي يمكنك إرسالها في فترة زمنية معينة. مع الـ Polling المستمر، ستصل لهذا الحد بسرعة كبيرة.

مثال بسيط لمبدأ الـ Polling (Pseudocode)

لو بدنا نكتب كود بسيط يوضح الفكرة، رح يكون شكله كالتالي:


// هذا ليس كود حقيقي، مجرد توضيح للفكرة
function startPollingForUpdates() {
  setInterval(async () => {
    try {
      const response = await fetch('https://api.supplier.com/v1/updates');
      const data = await response.json();

      if (data.hasNewUpdates) {
        // إذا كان هناك تحديثات، قم بمعالجتها
        processUpdates(data.updates);
      } else {
        // لا يوجد جديد، انتظر الجولة القادمة
        console.log('لا يوجد تحديثات جديدة...');
      }
    } catch (error) {
      console.error('حدث خطأ أثناء الاستعلام:', error);
    }
  }, 10000); // اسأل كل 10 ثواني
}

startPollingForUpdates();

هذا هو بالضبط ما كنا نفعله، حلقة لا نهائية من الأسئلة المنهكة.

الحل السحري: خطافات الويب (Webhooks)

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

ما هي خطافات الويب (Webhooks)؟

الـ Webhook هو آلية تسمح لتطبيق بإرسال معلومات إلى تطبيق آخر بشكل فوري عند وقوع حدث معين. هي عبارة عن “رد نداء” (Callback) عبر بروتوكول HTTP.

الـ Webhooks ببساطة: أنت تعطي رقم هاتفك (URL) لتطبيق آخر، وعندما يحدث شيء مهم، يقوم هذا التطبيق بالاتصال بك (إرسال طلب HTTP POST) وإخبارك بما حدث.

هذا يغير البنية من “اسحب” (Pull) في حالة الـ Polling إلى “ادفع” (Push). التطبيق المصدر “يدفع” البيانات إليك عند الحاجة فقط. وهذا يعني:

  • كفاءة في استهلاك الموارد: لا توجد طلبات ضائعة. يتم إرسال طلب فقط عند وجود بيانات فعلية.
  • تحديثات فورية (Real-time): تصلك المعلومة في نفس اللحظة التي يحدث فيها التغيير.
  • قابلية توسع ممتازة: السيرفر الخاص بك يتعامل مع الطلبات عند وصولها فقط، مما يجعله قادراً على خدمة عدد أكبر من الاتصالات.

كيف تعمل الـ Webhooks خطوة بخطوة؟

  1. التسجيل (Registration): أنت، كمطور، تذهب إلى الخدمة التي تريد استقبال إشعارات منها (مثل GitHub, Stripe, Slack) وتزودهم بعنوان URL خاص بتطبيقك. هذا الـ URL يسمى “Webhook Endpoint”.
  2. الحدث (The Event): يقع حدث معين في تلك الخدمة. مثلاً، عميل يدفع فاتورة عبر Stripe، أو مطور يرفع كود جديد على GitHub.
  3. الإشعار (The HTTP POST): تقوم الخدمة المصدر فوراً بتكوين طلب HTTP POST. هذا الطلب يحتوي على بيانات الحدث (تسمى الـ Payload) بصيغة JSON أو XML، ويتم إرساله إلى الـ URL الذي قمت بتسجيله.
  4. المعالجة (Action): يستقبل السيرفر الخاص بك هذا الطلب، يقرأ البيانات، ويتخذ الإجراء المناسب. مثلاً: تحديث قاعدة البيانات، إرسال بريد إلكتروني، تشغيل عملية بناء (build)، إلخ.

لنطبق عملياً: بناء أول Webhook Endpoint لك

الكلام النظري جميل، لكن خلينا نشوف كيف ممكن نطبق هذا بشكل عملي. لنبني مثالاً بسيطاً باستخدام Node.js و Express. الهدف هو استقبال إشعار من GitHub كلما قام شخص ما بإضافة “نجمة” (Star) لمشروعك.

1. تجهيز السيرفر المحلي (Node.js/Express)

أولاً، تأكد من وجود Node.js و npm، ثم قم بإنشاء مشروع جديد:


# إنشاء مجلد جديد والدخول إليه
mkdir my-webhook-server
cd my-webhook-server

# تهيئة مشروع node
npm init -y

# تثبيت مكتبة Express
npm install express

الآن، قم بإنشاء ملف `server.js` واكتب فيه الكود التالي:


const express = require('express');
const app = express();
const PORT = 3000;

// Middleware لقراءة الـ JSON القادم في جسم الطلب
app.use(express.json());

// هذا هو الـ Webhook Endpoint
app.post('/api/github-webhook', (req, res) => {
  const payload = req.body;
  
  // استخلاص المعلومات المهمة من الـ payload
  const action = payload.action;
  const repoName = payload.repository.full_name;
  const user = payload.sender.login;

  if (action === 'created') {
    console.log(`
      ---------------------------------
      🎉 نجمة جديدة على المستودع!
      المستودع: ${repoName}
      المستخدم: ${user}
      ---------------------------------
    `);
  }
  
  // مهم جداً: أرسل استجابة ناجحة فوراً
  res.status(200).send('Webhook received successfully!');
});

app.listen(PORT, () => {
  console.log(`السيرفر يستمع على المنفذ ${PORT}`);
});

2. تعريض السيرفر المحلي للإنترنت باستخدام `ngrok`

GitHub لا يستطيع الوصول إلى جهازك المحلي (localhost). لذلك، نحتاج إلى أداة مثل `ngrok` لإنشاء نفق آمن بين جهازك والإنترنت العام.

قم بتحميل `ngrok` وتشغيله في الطرفية (Terminal):


# شغّل السيرفر أولاً
node server.js

# في طرفية أخرى، شغّل ngrok
./ngrok http 3000

سيقوم `ngrok` بإعطائك عنوان URL عام (مثل `https://abcdef1234.ngrok.io`). انسخ هذا العنوان الذي ينتهي بـ `https`.

3. إعداد الـ Webhook على GitHub

  1. اذهب إلى المستودع (Repository) الذي تريد مراقبته على GitHub.
  2. اذهب إلى Settings > Webhooks.
  3. اضغط على “Add webhook”.
  4. في حقل “Payload URL”، الصق عنوان `ngrok` وأضف المسار الذي حددناه في الكود: `https://abcdef1234.ngrok.io/api/github-webhook`.
  5. في “Content type”، اختر `application/json`.
  6. في قسم “Which events would you like to trigger this webhook?”، اختر “Let me select individual events.” ثم اختر “Stargazers”.
  7. اضغط “Add webhook”.

الآن، اطلب من أي صديق (أو استخدم حساب آخر) أن يضيف نجمة لمستودعك. ستجد في طرفية السيرفر الخاص بك رسالة الترحيب التي كتبناها! لقد استقبلت أول إشعار من الـ Webhook بنجاح!

نصائح من “الختيار” (خبرة أبو عمر العملية)

بناء Webhook أمر سهل، لكن بناء نظام قوي يعتمد عليها يتطلب بعض الحكمة. إليكم بعض النصائح من الميدان:

1. الأمان أولاً: تحقق من صحة الـ Webhook

أي شخص يعرف عنوان الـ URL الخاص بك يمكنه إرسال طلبات مزيفة إليه. “مش كل من دق الباب تفتحله”. معظم الخدمات المحترمة (مثل GitHub و Stripe) تقوم بتوقيع طلبات الـ Webhook باستخدام مفتاح سري (Secret). وظيفتك هي التحقق من هذا التوقيع.

مثال للتحقق من توقيع GitHub (Node.js):


const crypto = require('crypto');
const GITHUB_SECRET = 'هذا_هو_المفتاح_السري_الذي_وضعته_في_جيت_هاب';

// Middleware للتحقق من التوقيع قبل معالجة الطلب
app.use('/api/github-webhook', (req, res, next) => {
  const signature = req.headers['x-hub-signature-256'];
  if (!signature) {
    return res.status(401).send('No signature provided.');
  }

  const hmac = crypto.createHmac('sha256', GITHUB_SECRET);
  const digest = 'sha256=' + hmac.update(JSON.stringify(req.body)).digest('hex');

  if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(digest))) {
    return res.status(401).send('Invalid signature.');
  }

  next();
});

2. استجب بسرعة، وعالج لاحقاً

الخدمة التي ترسل الـ Webhook تتوقع منك رداً سريعاً (مثل `200 OK`) لتتأكد أنك استلمت الإشعار. إذا استغرقت وقتاً طويلاً في معالجة البيانات، قد تعتبر الخدمة أن طلبها فشل وتقوم بإعادة إرساله، مما يسبب تكراراً للمعلومات.

الحل: استلم الطلب، ضعه في طابور مهام (Message Queue) مثل RabbitMQ أو Redis، وأرسل استجابة `200 OK` فوراً. ثم دع “عامل” (Worker) آخر يأخذ المهمة من الطابور ويعالجها في الخلفية.

3. تعامل مع الفشل والتكرار (Idempotency)

قد تفشل شبكتك للحظات، أو قد يقوم المُرسل بإعادة إرسال نفس الـ Webhook عن طريق الخطأ. يجب أن يكون الكود الخاص بك “Idempotent”، أي أن معالجة نفس الإشعار مرتين أو ثلاث لا يغير النتيجة النهائية. مثلاً، قبل إضافة سجل جديد في قاعدة البيانات، تحقق أولاً إذا كان معرف (ID) هذا الحدث موجوداً بالفعل.

4. التسجيل (Logging) هو صديقك الوفي

سجّل كل شيء: الطلبات الواردة، الـ Headers، الـ Payload، ونتائج المعالجة. عندما يفشل شيء ما في منتصف الليل، ستكون سجلاتك (Logs) هي المنقذ الوحيد الذي يخبرك بما حدث.

الخلاصة: متى تختار هذا أو ذاك؟ 🤔

بعد كل هذا الشرح، السؤال المنطقي هو: متى أستخدم Polling ومتى أستخدم Webhooks؟

  • استخدم Webhooks (الخيار المفضل) عندما:

    • تحتاج إلى بيانات فورية أو شبه فورية.
    • الخدمة المصدر تدعم Webhooks.
    • تريد بناء بنية تحتية فعالة وموجهة بالأحداث (Event-Driven Architecture).
    • الأحداث غير متكررة بشكل كبير (مثل إتمام عملية دفع، تحديث ملف شخصي).
  • استخدم Polling (كملاذ أخير) عندما:

    • الخدمة المصدر لا تدعم Webhooks (وهذا هو السبب الأقوى).
    • البيانات ليست حساسة للوقت ولا تحتاج أن تكون فورية.
    • تريد معرفة “حالة” شيء ما يتغير باستمرار (مثل سعر سهم يتغير كل ثانية).

في النهاية، الانتقال من عقلية “السؤال المستمر” إلى عقلية “الاستماع الذكي” هو نقلة نوعية في تطوير البرمجيات. الـ Webhooks ليست مجرد أداة، بل هي فلسفة في بناء أنظمة متجاوبة، فعالة، وقادرة على التوسع. لقد أنقذتنا من جحيم حقيقي، وأنا على يقين أنها ستفعل المثل لتطبيقاتكم.

أتمنى أن تكون هذه المقالة مفيدة لكم. الله يوفقكم في مشاريعكم. 🚀

أبو عمر

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

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

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

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

آخر المدونات

خوارزميات

البحث في قوائمي المرتبة كان يزحف: كيف أنقذني ‘البحث الثنائي’ من جحيم البطء الخطي؟

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

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

ميزانيتنا كانت تحترق: كيف أنقذتنا ‘نماذج الإحالة’ (Attribution Models) من جحيم تخمين القنوات الرابحة؟

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

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

من فوضى المكونات إلى نظام التصميم المتكامل: قصتنا لإنقاذ واجهات المستخدم من جحيم التضارب

أشارككم تجربتي كـ "أبو عمر" في الانتقال من واجهات فوضوية ومكررة إلى بيئة عمل منظمة بفضل "نظام التصميم". سنغوص في رحلتنا لبناء هذا النظام من...

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

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

أشارككم قصة حقيقية عن كيفية تراكم فواتير الخوادم الفارغة، وكيف كانت الحوسبة الخادومية (Serverless) هي طوق النجاة. سنغوص في هذا المفهوم الثوري، من هو وما...

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

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

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

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

طلباتنا كانت تضرب قاعدة البيانات بلا رحمة: كيف أنقذنا ‘التخزين المؤقت’ (Caching) من جحيم الاستجابة البطيئة؟

أشارككم قصة حقيقية من قلب المعركة البرمجية، يوم كادت قاعدة بياناتنا أن تنهار تحت وطأة الطلبات المتكررة. سنغوص في عالم التخزين المؤقت (Caching) وكيف كان...

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