जब आप Node.js के साथ काम कर रहे होते हैं, तो शुरुआत में एरर हैंडलिंग (error handling) बहुत आसान लगती है। आप एक रूट को try-catch में लपेट देते हैं, 500 स्टेटस कोड भेजते हैं, और क्लाइंट तय करता है कि आगे क्या करना है। यह मॉडल HTTP के लिए तो ठीक है, लेकिन जैसे ही आप बैकग्राउंड जॉब्स (background jobs) की ओर बढ़ते हैं, यह काम करना बंद कर देता है। एक क्यू सिस्टम (queue system) में, कोई क्लाइंट इंतज़ार नहीं कर रहा होता है। वहाँ केवल एक वर्कर (worker), एक पेलोड (payload), और Redis, RabbitMQ, या SQS में कहीं बढ़ता हुआ एक रिट्राय काउंटर (retry counter) होता है। यदि आप विफलताओं को उसी तरह संभालते हैं जैसे आप विफल वेब अनुरोधों (web requests) को संभालते हैं, तो आप केवल एक ट्रांजेक्शन ही नहीं खोएंगे। आप अपने पूरे पाइपलाइन को रोक देंगे, कंप्यूट रिसोर्स बर्बाद कर देंगे, या एक ही 'पॉइज़न्ड मैसेज' (poisoned message) पर अपने वर्कर्स को बार-बार क्रैश कर देंगे।

बैकग्राउंड जॉब्स में HTTP माइंडसेट काम नहीं करता

एक रिक्वेस्ट-रिस्पॉन्स साइकिल (request-response cycle) में, फीडबैक लूप तुरंत होता है। एक यूजर बटन क्लिक करता है, सर्वर एरर देता है, और यूजर को विफलता की स्क्रीन दिखती है। क्लीनअप (cleanup) सरल है। एक क्यू वर्कर आइसोलेशन (isolation) में रहता है। वह एक जॉब उठाता है, कुछ सेकंड या मिनटों तक उस पर काम करता है, और फिर सफलता की पुष्टि (acknowledgment) करता है। यदि बीच में कुछ गलत हो जाता है, तो क्यू को पता नहीं चलता कि क्यों। उसे बस इतना पता होता है कि कन्फर्मेशन नहीं मिला। आपकी कॉन्फ़िगरेशन के आधार पर, वह बार-बार कोशिश (retry) करेगा, शायद हमेशा के लिए। एक गलत तरीके से बनाया गया (malformed) पेलोड सैकड़ों बार वर्कर्स के बीच घूम सकता है, जिससे CPU बर्बाद होता है और उन वैध जॉब्स के पीछे छिप जाता है जिन्हें वास्तव में प्रोसेसिंग की आवश्यकता है।

विफलता के दो प्रकार

लचीली (resilient) क्यूज़ का पहला नियम यह है कि हर एरर को एक ही तरह से देखना बंद करें। आपको विफलताओं को होते ही दो समूहों में बाँटने की आवश्यकता है।

रिट्रायबल (Retryable) विफलताएँ क्षणिक (transient) होती हैं। नेटवर्क टाइमआउट, किसी थर्ड-पार्टी API से रेट लिमिट, या डेटाबेस कनेक्शन जो पूल खत्म होने के कारण रीसेट हो गया हो, इसके बारे में सोचें। ये दबाव में चल रहे एक जीवित सिस्टम के लक्षण हैं। वे दो मिनट बाद अगले प्रयास में सफल हो सकते हैं।

स्थायी (Permanent) विफलताएँ 'पॉइज़न पिल्स' (poison pills) होती हैं। इनमें गलत पेलोड, स्कीमा वैलिडेशन एरर, या किसी अपस्ट्रीम सर्विस द्वारा कॉन्ट्रैक्ट बदलने के कारण कोई आवश्यक फ़ील्ड गायब होना शामिल है। इन्हें बार-बार आज़माना पूरी तरह से बर्बादी है। वे सौवें प्रयास में भी बिल्कुल वैसे ही विफल होंगे।

यदि आपका catch ब्लॉक इन दोनों के बीच अंतर नहीं बता सकता, तो आपकी क्यू बिना किसी दिशा के काम कर रही है।

पैटर्न 1: Catch ब्लॉक पर एरर्स को वर्गीकृत करें

आपके वर्कर के catch ब्लॉक को फ़ाइल का सबसे सोच-समझकर लिखा गया कोड होना चाहिए। जब कोई एरर सामने आए, तो तुरंत उसकी जाँच करें। क्या एरर कोड ECONNRESET है या टाइमआउट है? इसे रिट्राय के लिए क्यू में डालें। क्या यह SyntaxError है, Joi वैलिडेशन रिजेक्शन है, या कोई मिसिंग फॉरेन की (foreign key) कंस्ट्रेंट है? इसे सीधे डेड-लेटर क्यू (dead-letter queue), या DLQ में भेज दें, और इसे अपनी रिट्राय लिमिट में न गिनें।

BullMQ और Bee Queue सहित अधिकांश Node.js क्यू लाइब्रेरीज़ आपको कस्टम बैकऑफ़ रणनीतियाँ (backoff strategies) और एरर हुक्स (error hooks) परिभाषित करने की अनुमति देती हैं। उनका उपयोग करें। एक स्थायी एरर को डिफ़ॉल्ट रूप से कभी भी तीन बार सोने और फिर से कोशिश करने की अनुमति नहीं दी जानी चाहिए। इसे मुख्य क्यू से निकाल दिया जाना चाहिए ताकि आपके बाकी जॉब्स चलते रहें। DLQ सटीक पेलोड और एरर कॉन्टेक्स्ट को सुरक्षित रखता है, जिससे आप बग ठीक करने या स्कीमा सुधारने के बाद बाद में उस जॉब को फिर से चला सकते हैं।

पैटर्न 2: Jitter के साथ Exponential Backoff

तुरंत रिट्राय करना आक्रामक है। यदि कोई डाउनस्ट्रीम डेटाबेस पहले से ही लोड के कारण संघर्ष कर रहा है, तो पचास वर्कर्स से हर दो सेकंड में उस पर हमला करना उसे पूरी तरह खत्म कर देगा। आपको पीछे हटने और सिस्टम को रिकवर होने के लिए जगह देने की ज़रूरत है।

Exponential backoff का उपयोग करें। पहली विफलता पर, एक सेकंड प्रतीक्षा करें। दूसरी पर, दो सेकंड। फिर चार, फिर आठ, और पाँच मिनट जैसी उचित सीमा तक। लेकिन केवल टाइमिंग ही पर्याप्त नहीं है। यदि प्रत्येक विफल जॉब बिल्कुल एक ही अंतराल का उपयोग करता है, तो बैकऑफ़ समाप्त होने पर वे सभी टकरा जाएंगे। वह सिंक्रोनाइज़्ड लहर, जिसे कभी-कभी 'thundering herd' कहा जाता है, रिकवर हो रहे सर्विस को ओवरवेल्म कर सकती है।

Jitter जोड़ें। अपने द्वारा गणना किए गए विलंब (delay) को एक रैंडम प्रतिशत, शायद दस से बीस प्रतिशत से थोड़ा बदल दें। चार सेकंड 4.2 या 4.7 बन जाता है। यह सरल रैंडमनेस रिट्राय स्पाइक को फैला देती है और आपके इंफ्रास्ट्रक्चर को लहरों में प्रहार होने से बचाती है।

पैटर्न 3: Idempotency के लिए डिज़ाइन करें

यहीं पर क्यू इंफ्रास्ट्रक्चर बिजनेस लॉजिक से मिलता है। एक ऐसी जॉब की कल्पना करें जो पेमेंट प्रोवाइडर के माध्यम से ग्राहक से शुल्क लेती है। वर्कर सफलतापूर्वक चार्ज पोस्ट करता है, लेकिन इससे पहले कि वह आपके डेटाबेस में सफलता दर्ज कर सके या जॉब को कन्फर्म कर सके, कनेक्शन टूट जाता है। क्यू विफलता देखती है। वह रिट्राय करती है। ग्राहक से दो बार शुल्क लिया जाता है।

In Node.js, prevent this by making every side effect idempotent. Generate an idempotency key from the job ID or a business-specific identifier. Before you create the charge or send the email or adjust inventory, check whether the work was already done. Pass that key all the way through to your database and to any third-party APIs that accept one. Structure your jobs so that running the same payload ten times produces the same outcome as running it once. This single habit eliminates an entire category of financial and data-integrity bugs.

Pattern 4: Treat Your Dead-Letter Queue Like a Dashboard

A DLQ is not a graveyard where bad jobs go to be forgotten. It is an operational tool, and it should be one of your most watched surfaces.

Set up alerts that fire when the DLQ depth increases. Even a single message in the DLQ often means your validation logic is broken, an upstream schema changed, or a downstream service is sending garbage you no longer recognize. These are exactly the signals you want to catch before customers start complaining. Build a dashboard that lets you inspect the raw payload, the stack trace, and the timestamp. Have a runbook ready: inspect the failure, patch the code, then replay the messages in the correct order. If your queue implementation supports it, alert on growth rate as well as absolute count, because one bad deploy can flood the DLQ within minutes.

Pattern 5: When in Doubt, Crash the Process

Node.js runs on a single event loop inside a V8 isolate. An unhandled promise rejection or an