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

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

بتذكر في واحد من المشاريع الأولى الكبيرة إلي، كنت شغال على منصة تعليمية بتسمح للمدرسين يرفعوا فيديوهات شروحات للطلاب. كل شي كان ماشي زي الحلاوة، التصميم حلو والوظائف الأساسية شغالة. المشكلة الكبيرة بلشت تظهر لما المدرس يرفع فيديو. بعد ما يكبس زر “رفع”، كانت الصفحة “تعلّق” أو تتجمد تماماً. شاشة بيضا ودوامة تحميل بتضل تلف وتلف… وأحياناً المتصفح نفسه يعطي رسالة خطأ “Request timed out”.

شو القصة؟ القصة إنه بعد رفع الفيديو، كان السيرفر تبعي يبدأ عملية طويلة ومعقدة: تحويل الفيديو (Transcoding) لعدة جودات مختلفة (1080p, 720p, 480p) عشان يناسب سرعات الإنترنت المختلفة عند الطلاب، وكمان كان يستخرج صورة مصغرة (Thumbnail) من الفيديو. هاي العملية كانت تاخد من دقيقة لخمس دقايق حسب طول الفيديو. وطول هاي المدة، المستخدم (المدرس) قاعد بستنى والصفحة مجمدة، لأنه السيرفر مشغول بالكامل بالعملية هاي ومش قادر يرجعله أي رد.

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

ما هو الجحيم الذي كنت أعيش فيه؟ (مشكلة العمليات المتزامنة)

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

هذا بالزبط اللي كان يصير معي. طلب المستخدم (HTTP Request) كان يوصل السيرفر، والسيرفر (الطباخ) يبدأ بالعملية الطويلة (طبخ الوجبة)، وما يرجع أي رد للمستخدم (Response) إلا لما العملية تخلص. النتيجة؟ تجربة مستخدم سيئة جداً وتجمد للواجهة.

البرمجة غير المتزامنة: بداية الخلاص

الحل يكمن في تغيير طريقة التفكير من متزامن إلى “غير متزامن” (Asynchronous). نرجع لمثال المطعم. في النظام غير المتزامن، أنت بتعطي طلبك للكاشير (وليس الطباخ مباشرة). الكاشير بسجل طلبك على ورقة (رسالة)، وبعلقها في مكان مخصص (قائمة الانتظار)، وبقلك مباشرة: “تمام، استلمنا طلبك، رح نناديلك لما يجهز”. أنت هلأ حر، بتقدر تقعد على طاولتك، تتصفح جوالك، أو تحكي مع صاحبك. في الخلفية، في طباخ (أو عدة طباخين) بياخدوا الطلبات من قائمة الانتظار هاي بالترتيب وببلشوا يشتغلوا عليها. لما وجبتك تجهز، حدا بناديلك تستلمها.

شايفين الفرق؟ أنت كمستخدم ما استنيت ولا دقيقة. تجربتك كانت سريعة وسلسة. هذا هو بالزبط سحر قوائم انتظار الرسائل.

قوائم انتظار الرسائل (Message Queues): المنقذ بالتفصيل

قائمة انتظار الرسائل هي ببساطة مكون برمجي وسيط، مثل ساعي البريد أو نظام الطلبات في المطعم. الفكرة هي فصل الأجزاء المختلفة من نظامك عن بعضها البعض. المكونات الأساسية لأي نظام بيستخدم قوائم الانتظar هي:

  • المنتِج (Producer): هو الجزء من نظامك اللي بينشئ المهمة. في قصتي، كان هو تطبيق الويب (Web Server) اللي بيستقبل طلب رفع الفيديو. مهمته بسيطة: بدل ما ينفذ المهمة الطويلة بنفسه، بيكتب “رسالة” تحتوي على كل المعلومات اللازمة لتنفيذها (مثلاً: “الرجاء تحويل الفيديو رقم 123 الموجود في المسار كذا”) وبيحطها في قائمة الانتظار.
  • قائمة الانتظار (Queue): هي المخزن المؤقت للرسائل. مثل طابور من الناس، الرسائل بتصطف فيه وبستنوا دورهم. هي بتضمن إنه ولا رسالة تضيع، وبتسلمهم بالترتيب (غالباً). أشهر الأمثلة على برامج بتوفر هاي الخدمة هي RabbitMQ, Redis, Amazon SQS, و Apache Kafka.
  • المستهلِك (Consumer / Worker): هو عبارة عن برنامج أو عملية منفصلة تماماً عن تطبيق الويب الرئيسي. مهمته الوحيدة في الحياة هي إنه يضل يراقب قائمة الانتظار. أول ما يلاقي رسالة جديدة، بياخدها وبيبدأ بتنفيذ المهمة الطويلة الموصوفة فيها (عملية تحويل الفيديو). ولما يخلص، ممكن يحدّث قاعدة البيانات، أو يرسل إيميل للمستخدم، أو أي شيء آخر.

الفكرة الجوهرية: تطبيقك الرئيسي يجب أن يكون سريعاً جداً في الرد على المستخدم. أي عملية تأخذ أكثر من نصف ثانية يجب التفكير جدياً في نقلها لتُنفذ في الخلفية عبر قائمة انتظار.

مثال عملي بالكود (Python, Celery, Redis)

عشان الصورة تكون أوضح، خلينا نشوف مثال بسيط باستخدام لغة Python ومكتبة Celery الشهيرة، مع استخدام Redis كـ “وسيط رسائل” (Message Broker).

أولاً، سنقوم بتعريف “المستهلك” أو العامل (Worker). سننشئ ملف اسمه tasks.py:


# tasks.py
import time
from celery import Celery

# نقوم بتهيئة Celery وربطه مع Redis كوسيط للرسائل
app = Celery('tasks', broker='redis://localhost:6379/0')

@app.task
def process_video(video_id):
    """
    هذه هي المهمة الطويلة التي سيتم تنفيذها في الخلفية.
    """
    print(f"بدأنا معالجة الفيديو رقم: {video_id}")
    
    # هنا نضع الكود الفعلي لتحويل الفيديو
    # للتجربة، سنقوم فقط بمحاكاة عملية طويلة باستخدام time.sleep()
    time.sleep(30)  # نم هنا لمدة 30 ثانية لمحاكاة عملية طويلة
    
    print(f"انتهت معالجة الفيديو رقم: {video_id}. تم بنجاح!")
    
    # هنا يمكننا تحديث قاعدة البيانات، مثلاً تغيير حالة الفيديو إلى "جاهز"
    return {"status": "success", "video_id": video_id}

ثانياً، في تطبيق الويب الرئيسي (المنتِج)، لنقل أنه تطبيق Flask، سنقوم باستدعاء هذه المهمة بشكل غير متزامن. ملف app.py:


# app.py
from flask import Flask, jsonify
from tasks import process_video

web_app = Flask(__name__)

@web_app.route('/upload-video', methods=['POST'])
def upload_video_endpoint():
    # هنا الكود الذي يستقبل الفيديو ويحفظه في مكان مؤقت
    # ويقوم بإنشاء سجل له في قاعدة البيانات ويعطيه ID فريد
    new_video_id = 123  # كمثال

    # *** السطر السحري هنا ***
    # بدلاً من تنفيذ المهمة مباشرة، نرسلها إلى قائمة الانتظار
    process_video.delay(new_video_id)

    # نرجع رد فوري وسريع للمستخدم
    return jsonify({
        "message": "تم استلام الفيديو بنجاح! سنقوم بمعالجته وإعلامك عند الانتهاء."
    }), 202 # 202 Accepted تعني "قبلنا الطلب وسننفذه لاحقاً"

if __name__ == '__main__':
    web_app.run(debug=True)

لتشغيل هذا النظام، نحتاج إلى تشغيل 3 أشياء في الطرفية (Terminal):

  1. خادم Redis.
  2. تطبيق الويب: python app.py
  3. العامل (Consumer) الذي سيراقب قائمة الانتظار: celery -A tasks worker --loglevel=info

الآن، عندما يقوم المستخدم بزيارة الرابط /upload-video، سيحصل على رد فوري في أقل من ثانية! وفي الخلفية، سترى في طرفية العامل (Celery worker) رسالة تفيد بأنه بدأ بمعالجة الفيديو، وبعد 30 ثانية، ستظهر رسالة أخرى تفيد بانتهاء المعالجة.

فوائد تتجاوز مجرد السرعة: التوسع وفك الاقتران

بعد ما طبقت هذا الحل، مش بس انحلت مشكلة تجمد الواجهة، اكتشفت إنه قوائم الانتظار أعطتني مزايا جبارة تانية:

1. القابلية للتوسع (Scalability)

تخيل لو المنصة التعليمية نجحت وصار عندي مئات المدرسين يرفعوا فيديوهات بنفس الوقت. العامل (Consumer) الواحد ما رح يلحق. الحل؟ بكل بساطة، بشغل كمان عامل، وعاملين، وعشرة! كل عامل جديد رح يبلش يسحب مهام من نفس قائمة الانتظار ويساعد في إنجاز الشغل المتراكم. بقدر أزيد أو أقلل عدد العمال حسب الضغط بدون ما ألمس الكود الرئيسي لتطبيق الويب. هذا هو معنى التوسع الأفقي (Horizontal Scaling).

2. الموثوقية والمتانة (Resilience & Reliability)

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

3. فك الاقتران (Decoupling)

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

نصائح أبو عمر العملية 📝

من خبرتي في التعامل مع هذه الأنظمة لسنوات، اسمحولي أقدملكم كم نصيحة على السريع:

  • اختر الأداة المناسبة: لا يوجد حل واحد يناسب الجميع. RabbitMQ ممتاز للمهام المعقدة ويتطلب موثوقية عالية. Redis أبسط وأسرع ويناسب إذا كانت مهامك بسيطة ولا تمانع فقدان بعضها في حالات نادرة جداً. Kafka وحش مختلف، مصمم لتدفق البيانات الهائلة (Streaming) أكثر من كونه مجرد قائمة مهام. ابدأ بالبسيط (مثل Redis) ثم انتقل للأعقد عند الحاجة.
  • اجعل مهامك “Idempotent”: هذه كلمة معقدة لمعنى بسيط. يجب أن تكون مهمتك مصممة بحيث لو تم تنفيذها مرتين بالخطأ (بسبب فشل ما)، لا تسبب مشكلة. مثلاً، بدلاً من “إضافة 10 نقاط للمستخدم”، اجعل المهمة “تحديد نقاط المستخدم لتصبح 100”. لو تنفذت مرتين، النتيجة النهائية واحدة.
  • راقب ثم راقب ثم راقب: يجب أن يكون لديك نظام مراقبة (Monitoring) يريك طول قائمة الانتظار. إذا كان طول الطابور يزداد باستمرار، فهذا يعني أن عمالك لا يلحقون على الشغل، وتحتاج لإضافة المزيد منهم.
  • ليس كل شيء يحتاج قائمة انتظار: لا تفرط في استخدامها. العمليات السريعة التي تنتهي في أجزاء من الثانية (مثل تحديث اسم المستخدم) لا تحتاج لكل هذه التعقيدات. استخدمها فقط للعمليات التي تشعر أنها تبطئ تجربة المستخدم.

الخلاصة

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

إذا كنت تعاني من عمليات بطيئة تؤثر على تجربة المستخدم، أو تفكر في كيفية بناء تطبيقك القادم ليكون جاهزاً للنجاح والضغط العالي، فأنصحك بشدة أن تبدأ رحلتك مع عالم قوائم انتظار الرسائل. قد تبدو معقدة في البداية، لكن الفائدة التي ستحصل عليها لا تقدر بثمن. بالتوفيق يا جماعة! 💪

أبو عمر

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

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

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

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

آخر المدونات

الحوسبة السحابية

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

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

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

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

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

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

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

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

2 أبريل، 2026 قراءة المزيد
البنية التحتية وإدارة السيرفرات

تطبيقي كان يعمل على جهازي فقط: كيف أنقذتني ‘الحاويات’ (Containers) من جحيم ‘تعارض البيئات’؟

أشارككم قصة حقيقية عن كابوس "عندي شغال!" وكيف أصبحت تقنيات الحاويات مثل Docker أداتي السحرية لإنهاء صراعات البيئات المختلفة. هذه المقالة دليل عملي لكل مبرمج...

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

فريقي كان يخشى ارتكاب الأخطاء: كيف أنقذني بناء ‘الأمان النفسي’ من جحيم الإبداع المكبوت؟

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

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

تحديثاتي كانت تحطم الميزات القديمة: كيف أنقذتني ‘الاختبارات التراجعية الآلية’ من جحيم الخوف عند كل إصدار؟

أشارككم قصتي مع الخوف من تحديث البرمجيات وكيف كانت التحديثات الجديدة تكسر الميزات القديمة دون علمي. اكتشفوا معي كيف أصبحت "الاختبارات التراجعية الآلية" (Automated Regression...

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