من جحيم الـ Polling إلى نعيم الـ Webhooks: كيف أنقذنا أنظمتنا من الاستجداء المستمر؟

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

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

كتبنا سكربت بسيط، كل 5 ثواني يروح يسأل بوابة الدفع: “يا بوابة الدفع، شو صار بالطلبية رقم 123؟ اندفعت؟”، “طيب والطلبية 124؟”، “طيب و125؟”. في الأيام الأولى والأسبوع الأول، كان الوضع “عال العال” والنظام شغال زي الحلاوة. بس لما كبر المشروع وزادت الطلبات، بلشت المصايب. السيرفر صار يصيح من كثرة الطلبات اللي طالعة منه، واستهلاك الموارد صار بالسما. وفوق كل هاد، بوابة الدفع بلشت تبعتلنا تحذيرات إنه رح توقف حسابنا بسبب تجاوزنا للـ Rate Limit (الحد المسموح للطلبات في الدقيقة). كنا قاعدين بنشرب قهوة والمدير التقني دخل علينا وجهه أصفر، وقال: “يا جماعة، السيرفرات رح توقع، شو القصة؟!”.

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

ما هو الـ Polling؟ أو “طريقة السؤال كل شوي”

قبل ما نغوص في الحل، خلينا نفهم أصل المشكلة. الـ Polling (الاستعلام المستمر) هو ببساطة إنك كـ “عميل” (Client)، زي السيرفر تبعنا، تضلك تسأل “الخادم” (Server)، زي بوابة الدفع، بشكل متكرر: “هل في إشي جديد؟”، “هل تغيرت الحالة؟”، “هل وصلت البيانات؟”.

تخيل حالك بتستنى مكالمة مهمة، وبدل ما تستنى التلفون يرن، بتمسك التلفون كل 10 ثواني وبتتصل على حالك عشان تشوف إذا في حدا حاول يرن عليك! منطق غريب، صح؟ هاد هو الـ Polling بالضبط.

في عالم الكود، كان شكله إشي زي هيك (مثال بسيط باستخدام JavaScript):


// Polling Example in JavaScript
setInterval(async () => {
  try {
    // كل 5 ثواني، بنبعت طلب لنشوف حالة الطلبية
    const response = await fetch('https://api.payment-gateway.com/orders/123');
    const data = await response.json();

    if (data.status === 'paid') {
      console.log('الدفع تم بنجاح! تحديث حالة الطلبية...');
      // هنا نوقف الـ Polling ونحدث قاعدة البيانات
      // clearInterval(...)
    } else {
      console.log('لسه الحالة قيد الانتظار...');
    }
  } catch (error) {
    console.error('حدث خطأ أثناء الاستعلام:', error);
  }
}, 5000); // 5000 milliseconds = 5 seconds

جحيم الـ Polling: ليش هو سيء؟

طريقتنا هاي كانت بتسبب ثلاث مشاكل رئيسية:

  • استهلاك فظيع للموارد: كل طلب API يعني استهلاك للمعالج (CPU)، للذاكرة (Memory)، وللشبكة (Network)، سواء على سيرفرك أو على سيرفر الخدمة اللي بتسألها. تخيل آلاف الطلبات بتتسأل عن حالتها كل كم ثانية… كارثة حقيقية.
  • تأخير في الحصول على البيانات: حتى لو بتسأل كل 5 ثواني، لو الدفع تم في الثانية الأولى، أنت ما رح تعرف إلا بعد 4 ثواني. بياناتك دايماً متأخرة بمقدار الفترة الزمنية اللي حددتها.
  • تجاوز حدود الاستخدام (Rate Limiting): معظم الـ APIs المحترمة بتفرض حد على عدد الطلبات اللي بتقدر تبعتها في الدقيقة أو الساعة. مع الـ Polling، رح توصل لهاد الحد بسرعة البرق، والنتيجة؟ حظر مؤقت أو حتى دائم لحسابك.

الحل السحري: Webhooks أو “لما يصير إشي، خبرني!”

الـ Webhook هو عكس الـ Polling تماماً. بدل ما أنت تروح تسأل، بتعطي للخدمة الثانية (بوابة الدفع في مثالنا) عنوانك (URL)، وبتحكيلها: “اسمعي، بس يصير حدث معين عندي (مثلاً الدفع ينجح)، لا تغلب حالك، بس ابعتيلي رسالة على هاد العنوان مع كل التفاصيل”.

الفكرة هاي معروفة في عالم البرمجة بـ “الهندسة القائمة على الأحداث” (Event-Driven Architecture). أنت ما بتسأل، أنت بتتفاعل مع الأحداث لما تصير. وهيك، بدل ما تتصل على مطعم البيتزا كل دقيقة تسألهم “خلصت طلبيتي؟”، المطعم هو اللي برن عليك لما الطلبية تجهز. منطقي وأكثر كفاءة، أليس كذلك؟

كيف تعمل الـ Webhooks؟

الآلية بسيطة جداً ومكونة من ثلاث خطوات:

  1. أنت (تطبيقك): بتجهز عنوان URL خاص في تطبيقك (مثلاً: https://my-store.com/webhooks/payment-updates). هذا العنوان يسمى “Webhook Endpoint”.
  2. أنت (في لوحة تحكم الخدمة الأخرى): بتروح على لوحة تحكم بوابة الدفع، وبتضيف الـ URL تبعك في قسم الـ Webhooks، وبتحدد الأحداث اللي بدك ياهم يخبروك عنها (مثلاً: payment.succeeded).
  3. الخدمة الأخرى (بوابة الدفع): لما يتم الدفع بنجاح، السيرفر تبعهم تلقائياً بيبعت طلب HTTP من نوع POST على الـ URL تبعك. هذا الطلب بيحتوي على جسم (Body) فيه كل تفاصيل الحدث بصيغة JSON.

تطبيقك بكون بستنى على هاد العنوان، وبس يستقبل الطلب، بقرأ البيانات وبعمل الإجراء اللازم (مثل تحديث حالة الطلبية في قاعدة البيانات).

بناء أول Webhook Endpoint لك: مثال عملي

خلينا نشوف مثال عملي وبسيط لبناء Webhook Endpoint باستخدام Node.js و Express.js، لأنه إطار عمل خفيف وممتاز لهيك مهام.

الخطوة الأولى: تجهيز السيرفر

أولاً، تأكد إنك ثبتت Express. ثم أنشئ ملف سيرفر أساسي.


// server.js
const express = require('express');
const app = express();
const PORT = 3000;

// Middleware مهم جداً عشان Express يفهم الـ JSON اللي جاي في جسم الطلب
// ملاحظة: بعض خدمات الـ Webhook تتطلب قراءة الـ Raw Body للتحقق من التوقيع، سنتحدث عن هذا لاحقاً
app.use(express.json());

app.get('/', (req, res) => {
  res.send('سيرفر الـ Webhooks شغال!');
});

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

الخطوة الثانية: إنشاء الـ Endpoint

الآن، لنضف المسار (Route) الذي سيستقبل طلبات الـ Webhook.


// ... باقي كود السيرفر

// هذا هو الـ Endpoint اللي رح تعطيه لبوابة الدفع
app.post('/webhooks/payment-updates', (req, res) => {
  console.log('Webhook جديد وصل!');
  
  // الـ payload أو البيانات اللي بعتتها بوابة الدفع بتكون في req.body
  const payload = req.body;
  console.log('البيانات:', payload);

  // هنا تبدأ بمعالجة البيانات
  // مثال: التحقق من نوع الحدث
  if (payload.event === 'payment.succeeded') {
    const orderId = payload.data.order_id;
    const amount = payload.data.amount;
    console.log(`تم دفع الطلبية رقم ${orderId} بنجاح بمبلغ ${amount}`);
    // ... اكتب الكود لتحديث قاعدة بياناتك هنا
  }

  // **مهم جداً:** أرجع استجابة ناجحة (200 OK) بسرعة
  // هذا يخبر الخدمة أنك استلمت الـ Webhook بنجاح
  res.status(200).send('Webhook received');
});

الخطوة الثالثة: تأمين الـ Endpoint (نصيحة احترافية)

أي شخص بيعرف عنوان الـ Endpoint تبعك بيقدر يبعتلك طلبات مزيفة. لهذا السبب، معظم الخدمات المحترمة مثل Stripe وGitHub وShopify تستخدم “توقيعاً” (Signature) لتأكيد أن الطلب قادم منهم فعلاً.

الآلية كالتالي: الخدمة بتنشئ “Secret Key” خاص فيك. مع كل Webhook بتبعته، بتستخدم هاد المفتاح لتوقيع البيانات وبتبعتلك التوقيع في الـ Headers (مثلاً X-Stripe-Signature). مهمتك هي إنك تعيد حساب التوقيع عندك باستخدام نفس المفتاح وتقارنه بالتوقيع اللي وصلك. إذا تطابقوا، فالطلب أصلي.

نصيحة من أبو عمر: لا تتجاهل خطوة التحقق من التوقيع أبداً في بيئة الإنتاج (Production)! تجاهلها يعني ترك باب خلفي مفتوح للهجمات.

المثال التالي يوضح الفكرة (الكود يختلف قليلاً حسب الخدمة، لكن المبدأ واحد):


const crypto = require('crypto');
const webhookSecret = 'whsec_...'; // هذا المفتاح السري تأخذه من بوابة الدفع

// ...

// ملاحظة: للتحقق من التوقيع، تحتاج للـ Raw Body وليس الـ JSON
// لذلك، قد تحتاج لتعديل الـ Middleware قليلاً
app.post('/webhooks/secure-payment-updates', express.raw({type: 'application/json'}), (req, res) => {
    const signature = req.headers['stripe-signature']; // اسم الـ header يختلف

    try {
        const event = crypto.webhooks.constructEvent(
            req.body, // هنا نستخدم الـ Raw Body (Buffer)
            signature,
            webhookSecret
        );

        // إذا لم يحدث خطأ، فالتوقيع صحيح والطلب آمن
        console.log('Webhook موثوق وصل:', event);

        // الآن يمكنك معالجة الـ event.data بأمان
        if (event.type === 'payment_intent.succeeded') {
            // ...
        }

        res.status(200).send('Success');

    } catch (err) {
        console.log(`⚠️  فشل التحقق من توقيع الـ Webhook: ${err.message}`);
        return res.status(400).send('Webhook Error: Invalid signature');
    }
});

نصائح من خبرة أبو عمر

بعد سنوات من التعامل مع الـ Webhooks، تعلمت كم درس “على جلدي” كما يقال. إليكم أهمها:

  • نصيحة 1: لا تثق بالـ Webhook دائماً: الشبكات غير موثوقة. ممكن الـ Webhook ما يوصلك أبداً (سيرفرك كان واقع، مشكلة شبكة، …إلخ). الحل؟ ابنِ نظام “مصالحة” (Reconciliation). مثلاً، شغل سكربت Polling خفيف جداً مرة كل يوم بالليل، يسأل عن حالة كل الطلبات اللي لسه “قيد الانتظار” من 24 ساعة. هذا يضمن لك التقاط أي تحديثات ضائعة.
  • نصيحة 2: اجعل معالجة الـ Webhook سريعة جداً: الخدمة اللي بتبعت الـ Webhook بتتوقع منك رد 200 OK خلال ثوانٍ قليلة. إذا تأخرت، رح تعتبر إنك فشلت في الاستلام ورح تحاول تبعت الطلب مرة ثانية، مما يسبب تكراراً للمعلومات. القاعدة الذهبية: استلم الطلب، تحقق من توقيعه، ضعه في طابور مهام (Message Queue) مثل RabbitMQ أو AWS SQS، ثم أرجع استجابة 200 OK فوراً. دع “عامل” (Worker) منفصل يأخذ المهمة من الطابور ويعالجها براحته.
  • نصيحة 3: استخدم أدوات لتجربة الـ Webhooks محلياً: كيف ممكن بوابة دفع على الإنترنت تبعت طلب لسيرفر شغال على جهازك (localhost)؟ مستحيل مباشرة. هنا تأتي روعة أدوات مثل ngrok. هي أداة بسيطة بتعطيك رابط عام على الإنترنت، وأي طلب بيوصل على هاد الرابط بتحوله مباشرة إلى جهازك على بورت معين. هذا يسمح لك بتجربة وتصحيح أخطاء الـ Webhooks على جهازك المحلي قبل رفع الكود للسيرفر.

الخلاصة: ارتاح وخلي الخبر يجيك لعندك! 🏁

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

باختصار:

  • استخدم الـ Polling (بحذر شديد): فقط إذا كانت الخدمة لا تدعم الـ Webhooks، أو كآلية احتياطية ثانوية.
  • استخدم الـ Webhooks: في 99% من الحالات. هي الحل الأمثل للأنظمة الحديثة التي تتطلب كفاءة عالية، استجابة لحظية، وقابلية للتوسع.

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

أبو عمر

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

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

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

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

آخر المدونات

تسويق رقمي

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

كنا نصرخ في فراغ رقمي ورسائلنا لا تصل. في هذه المقالة، أشارككم قصة حقيقية كيف استخدمنا الذكاء الاصطناعي وتقنيات التخصيص الفائق (Hyper-personalization) لتحويل حملاتنا التسويقية...

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

الهمسات الرقمية: كيف تحوّل التفاعلات الدقيقة (Microinteractions) تجربة المستخدم من عادية إلى ساحرة؟

أنا أبو عمر، وفي هذه المقالة سأشارككم سرّاً من أسرار التصميم الاحترافي. سنتحدث عن "الهمسات الرقمية" أو التفاعلات الدقيقة (Microinteractions)، تلك التفاصيل الصغيرة التي تحوّل...

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

كانت استعلاماتنا تبحث في كل صف: كيف أنقذتنا ‘فهارس قواعد البيانات’ من جحيم المسح الكامل للجداول (Full Table Scans)؟

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

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

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

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

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

كان طلب واحد يُجمّد النظام بأكمله: كيف أنقذتنا ‘طوابير الرسائل’ من جحيم المهام المتزامنة؟

أشارككم قصة حقيقية عن يوم كاد فيه طلب واحد أن يُسقط نظامنا بالكامل، وكيف كانت "طوابير الرسائل" (Message Queues) هي طوق النجاة. سنتعمق في فهم...

6 مايو، 2026 قراءة المزيد
التكنلوجيا المالية Fintech

كان المحتالون يسبقوننا بخطوة: كيف أنقذنا ‘التعلم الآلي’ شركاتنا من جحيم الخسائر المالية؟

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

6 مايو، 2026 قراءة المزيد
ادارة الفرق والتنمية البشرية

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

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

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