Order confirm হওয়ার পর customer-কে email আর SMS পাঠাতে হয়। Email serverটা সেদিন ধীর - ৪ সেকেন্ড লাগল। আপনার API-ও ৪ সেকেন্ড আটকে রইল, customer ঘূর্ণায়মান চাকা দেখতে দেখতে ভাবল order হলোই না, আবার button চাপল - দুটো order! আসল সমস্যাটা এখানে: যেই কাজের ফলাফল user-কে সঙ্গে সঙ্গে দিতেই হবে না, সেটা request-এর ভিতরে রাখাই ভুল।
Queue-র ধারণা - লাইনে দাঁড় করানো
Queue হলো কাজের লাইন। API শুধু কাজটা লাইনে রেখে ('এই order-এর email পাঠাও') সঙ্গে সঙ্গে response দিয়ে দেয়। পেছনে আলাদা একটা worker সেই লাইন থেকে একটা একটা কাজ তুলে করে। User-এর অভিজ্ঞতা হয় ঝটপট, আর ধীর কাজগুলো নিজের গতিতে পেছনে হতে থাকে। BullMQ এই কাজটাই করে - ভিতরে ভিতরে Redis ব্যবহার করে, যেটা আগের পর্বেই বসানো হয়ে গেছে।
import { Queue, Worker } from "bullmq";
const emailQueue = new Queue("email", { connection: redis });
// API-র ভিতরে - শুধু লাইনে রাখা, পাঠানো নয়
await emailQueue.add("order-confirmation", { orderId, email });
res.status(201).json({ success: true, data: order });
// আলাদা worker - আসল পাঠানোর কাজ এখানে
new Worker("email", async (job) => {
await sendOrderEmail(job.data.orderId, job.data.email);
}, { connection: redis });Retry - ব্যর্থ হলেই হাল ছাড়া নয়
Email server সাময়িক ডাউন থাকতেই পারে। Queue-র সৌন্দর্য হলো ব্যর্থ job আবার চেষ্টা করা যায় - যেমন ৩ বার, প্রতিবার একটু বেশি অপেক্ষা করে (backoff)। তবু ব্যর্থ হলে job-টা failed অবস্থায় থেকে যায়, যাতে পরে দেখে হাতে ঠিক করা বা আবার চালানো যায়। কোনো job চুপচাপ হারিয়ে যায় না - এটাই request-এর ভিতরে করার চেয়ে বড় সুবিধা।
কোন কাজ queue-তে যাবে বোঝার নিয়ম: কাজটা ধীর হলে, বাইরের সার্ভিসের উপর নির্ভর করলে (email, SMS, payment gateway), বা ব্যর্থ হলে আবার চেষ্টার সুযোগ চাইলে - queue-তে দিন। যার উত্তর ছাড়া response-ই দেওয়া যায় না (যেমন login check) - সেটা request-এর ভিতরেই থাকবে।
সবাই যে ভুলটা করে
সবচেয়ে বেশি দেখা ভুল: email/SMS পাঠানো, ছবি process করা বা report বানানোর মতো ধীর কাজ controller-এর ভিতরে করা। ফলে API ধীর, timeout বাড়ে, আর বাইরের সার্ভিস ডাউন হলে আপনার পুরো API-ই আটকে যায়।
আজকের Practice
Order তৈরি হলে confirmation email পাঠানোর কাজটা BullMQ queue-তে সরিয়ে নিন (আসল email না পাঠিয়ে আপাতত console-এ log করলেও হবে)। Worker-এ ইচ্ছা করে একবার error ঘটিয়ে দেখুন retry হচ্ছে কিনা।
Interview-এ কীভাবে বলবেন
ধীর বা বাইরের সার্ভিসনির্ভর কাজ আমি queue-তে পাঠাই - API শুধু job যোগ করে সঙ্গে সঙ্গে response দেয়, worker পেছনে কাজটা করে। BullMQ-তে retry আর backoff থাকে, তাই সাময়িক ব্যর্থতায় কাজ হারায় না; শেষ পর্যন্ত ব্যর্থ হলে failed job হিসেবে থেকে যায়, পরে দেখা যায়।