مقدمة: لماذا نحتاج إلى قوائم المهام في JavaScript؟
\nفي تطوير الويب الحديث، غالبًا ما تواجه التطبيقات مهامًا لا يمكن تنفيذها فورًا ضمن طلب HTTP واحد. إرسال رسائل البريد الإلكتروني، معالجة الصور، إنشاء تقارير PDF أو المزامنة مع واجهات برمجة التطبيقات الخارجية - كل هذه الأمور تستغرق وقتًا وقد تؤدي إلى "تعليق" الخادم إذا تم تنفيذها بشكل متزامن.
\nقوائم المهام (Task Queues) تحل هذه المشكلة. فهي تسمح بتأجيل تنفيذ العمليات كثيفة الاستخدام للموارد ومعالجتها بشكل غير متزامن في الخلفية. في هذه المقالة، سنشرح كيفية إنشاء وإدارة قوائم المهام في بيئة Node.js باستخدام المكتبات الشائعة.
\n\n1. أساسيات العمل مع القوائم في Node.js
\nقائمة المهام هي بنية بيانات تعمل وفق مبدأ FIFO (أول من يدخل، أول من يخرج). يتم إضافة المهام إلى نهاية القائمة، ويتم معالجتها من البداية. في سياق Node.js، هذا يعني أن الخادم الخاص بك يمكنه الرد بسرعة على المستخدم ("تم استلام المهمة للمعالجة")، بينما سيتم تنفيذ المهمة نفسها لاحقًا.
\nللعمل مع القوائم في Node.js، يتم استخدام مكتبات متخصصة تعتمد على مخازن خارجية (غالبًا Redis). دعنا نلقي نظرة على الأكثر شيوعًا:
\n- \n
- Bull - مكتبة حديثة وسريعة ومستقرة تعتمد على Redis. \n
- Kue - مكتبة أقدم ولكنها لا تزال شائعة مع واجهة ويب مدمجة. \n
سنركز على Bull لأنها أصبحت المعيار الفعلي للمشاريع الجديدة.
\n\n1.1 تثبيت واستخدام Bull
\nللبدء، قم بتثبيت التبعيات اللازمة:
\nnpm install bull ioredis\nالآن لننشئ قائمة بسيطة:
\nconst Queue = require('bull');\nconst myQueue = new Queue('emailQueue', {\n redis: {\n host: '127.0.0.1',\n port: 6379\n }\n});\n\n// إضافة مهمة إلى القائمة\nmyQueue.add({\n to: 'user@example.com',\n subject: 'رسالة ترحيبية',\n body: 'مرحبًا بك في موقعنا!'\n});\n\nconsole.log('تمت إضافة المهمة إلى القائمة');\nفي هذا المثال، أنشأنا قائمة باسم emailQueue وأضفنا إليها مهمة واحدة - إرسال بريد إلكتروني. المهمة لم يتم تنفيذها بعد، إنها فقط تنتظر معالجها.
2. معالجة المهام من القائمة
\nلكي تبدأ المهام في التنفيذ، نحتاج إلى معالج (consumer). سيقوم "بالاستماع" إلى القائمة وأخذ المهام منها للتنفيذ.
\nلننشئ ملف worker.js:
const Queue = require('bull');\nconst emailQueue = new Queue('emailQueue', {\n redis: { host: '127.0.0.1', port: 6379 }\n});\n\n// دالة المعالجة\nemailQueue.process(async (job) => {\n const { to, subject, body } = job.data;\n console.log(`جارٍ إرسال البريد الإلكتروني إلى ${to}...`);\n \n // محاكاة إرسال البريد الإلكتروني (في مشروع حقيقي سيكون هناك nodemailer)\n await new Promise(resolve => setTimeout(resolve, 2000));\n \n console.log(`تم إرسال البريد الإلكتروني "${subject}" إلى ${to}`);\n return { status: 'sent', email: to };\n});\n\nconsole.log('تم تشغيل المعالج وهو ينتظر المهام...');\nقم بتشغيل هذا السكريبت، ثم أضف مهمة من المثال الأول. سترى كيف تتم معالجة المهمة.
\n\n2.1 معالجة الأخطاء وإعادة المحاولة
\nفي المشاريع الحقيقية، قد تفشل المهام (على سبيل المثال، خادم SMTP غير متاح). يوفر Bull آلية مدمجة لإعادة المحاولة:
\nemailQueue.add(\n { to: 'user@example.com', subject: 'رسالة مهمة' },\n { \n attempts: 5, // عدد المحاولات\n backoff: { type: 'exponential', delay: 2000 } // تأخير أسي\n }\n);\n\n// في المعالج يمكن معالجة الفشل\nemailQueue.on('failed', (job, err) => {\n console.error(`فشلت المهمة ${job.id}: ${err.message}`);\n});\n\n3. الميزات المتقدمة للقوائم
\nيوفر Bull العديد من الوظائف المفيدة لإدارة المهام.
\n\n