المستوى المطلوب: متوسط. لو انت مبتدئ، مكمّل معانا عادي — كل مفهوم هنا متشرح بمثال بسيط الأول، وبعده بالشكل التقني الدقيق.
خلّي الطلب يرد فورًا وسيب الشغل التقيل للطابور
لو الـ endpoint اللي بيعمل تسجيل مستخدم بياخد 30 ثانية عشان بيبعت إيميل ترحيب ويعالج صورة، المستخدم بيقعد يبصّ في شاشة بيضا، وتحت الضغط بتبدأ أخطاء 504 timeout. الحل مش سيرفر أقوى. الحل إنك تفصل الشغل التقيل عن الطلب: الـ API يضيف "مهمة" في طابور ويرد فورًا، وعملية تانية (Worker) تنفّذها في الخلفية.
المشكلة باختصار
تخيّل مطعم. الكاشير اللي بياخد الطلب هو نفسه اللي بيطبخ. كل زبون لازم يستنى الأكل يخلص قبل ما الكاشير يشوف اللي بعده. الطابور بيطول والناس بتزهق. الحل البديهي: الكاشير ياخد الطلب، يعلّقه في مشبك المطبخ، ويقول "تحت التنفيذ"، والطباخين ورا يشتغلوا بالتوازي.
بالتفاصيل التقنية: Node.js بيشتغل على event loop بخيط واحد. أي شغل متزامن تقيل (إرسال SMTP، معالجة صورة بـ Sharp، توليد PDF) بيحجز الخيط ويمنع باقي الطلبات من الرد. لما تحوّل الشغل ده لمهمة في طابور، الـ API بيرجع رد 202 Accepted في مللي ثانية، والـ Worker بيقرأ المهمة من Redis وينفّذها في عملية منفصلة.
الافتراض هنا: إن شغلك التقيل (إيميلات، صور، تقارير) مش لازم يخلص قبل ما ترد على المستخدم، وإن Redis واحد يكفي لحملك — وده صحيح لعشرات آلاف المهام في الدقيقة على جهاز متواضع. لو محتاج نتيجة فورية في نفس الطلب، ده سيناريو تاني نتكلم عنه في الآخر.
الخطوات: ابنيه في أقل من 60 سطر
هنستخدم BullMQ — أشهر مكتبة طوابير في Node.js، مبنية فوق Redis. السيناريو: موقع فيه 50 ألف تسجيل في اليوم، كل تسجيل بيبعت إيميل ترحيب.
- شغّل Redis وثبّت المكتبة. Redis هو مخزن المهام. أسرع طريقة بـ Docker.
docker run -d --name redis -p 6379:6379 redis:7
npm install bullmq- عرّف الطابور (Producer side). ده اللي الـ API هيستخدمه عشان يضيف مهام.
// queue.js
import { Queue } from 'bullmq';
const connection = { host: '127.0.0.1', port: 6379 };
export const emailQueue = new Queue('emails', { connection });