TypeScript में कार्य कतारों के साथ काम करना: व्यावहारिक रूप से
\nआधुनिक वेब अनुप्रयोगों में, उपयोगकर्ता के मुख्य थ्रेड को ब्लॉक किए बिना, लंबी या संसाधन-गहन संचालन को एसिंक्रोनस रूप से निष्पादित करने की आवश्यकता अक्सर उत्पन्न होती है। ईमेल न्यूज़लेटर भेजना, PDF रिपोर्ट जनरेट करना, अपलोड की गई छवियों को प्रोसेस करना - ये सभी पृष्ठभूमि कार्यों में स्थानांतरित करने के लिए आदर्श उम्मीदवार हैं। कार्य कतार (task queue) एक सिद्ध आर्किटेक्चरल पैटर्न है जो ऐसे संचालन के विश्वसनीय निष्पादन को व्यवस्थित करने की अनुमति देता है। इस लेख में, हम लोकप्रिय लाइब्रेरी और दृष्टिकोणों का उपयोग करके, व्यावहारिक रूप से TypeScript में कार्य कतार बनाने और उपयोग करने का तरीका समझेंगे।
\nहम एक सरल कतार बनाने, प्राथमिकताओं के साथ काम करने, त्रुटि प्रबंधन और BullMQ लाइब्रेरी के माध्यम से Redis के साथ एकीकरण पर विचार करेंगे। सभी उदाहरण सख्त टाइपिंग पर जोर देने के साथ TypeScript में लिखे जाएंगे।
\n\n1. मूल बातें: एक सरल कार्य कतार बनाना
\nशुरू करने के लिए, बिना किसी बाहरी निर्भरता के एक सरल कार्य कतार लागू करते हैं। इससे काम के बुनियादी सिद्धांतों को समझने में मदद मिलेगी। हमारी कतार फ़ंक्शन-कार्यों को संग्रहीत करेगी और उन्हें क्रमिक रूप से निष्पादित करेगी।
\ntype Task<T> = () => Promise<T>;\n\ninterface TaskItem<T> {\n task: Task<T>;\n resolve: (value: T | PromiseLike<T>) => void;\n reject: (reason?: any) => void;\n}\n\nclass SimpleQueue {\n private queue: TaskItem<any>[] = [];\n private isProcessing = false;\n\n add<T>(task: Task<T>): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n this.queue.push({ task, resolve, reject });\n this.process();\n });\n }\n\n private async process(): Promise<void> {\n if (this.isProcessing || this.queue.length === 0) return;\n this.isProcessing = true;\n\n const item = this.queue.shift()!;\n try {\n const result = await item.task();\n item.resolve(result);\n } catch (error) {\n item.reject(error);\n } finally {\n this.isProcessing = false;\n this.process();\n }\n }\n}\n\n// उपयोग\nconst queue = new SimpleQueue();\n\nqueue.add(async () => {\n console.log('कार्य 1 शुरू हुआ');\n await new Promise(r => setTimeout(r, 1000));\n console.log('कार्य 1 पूरा हुआ');\n return 'परिणाम 1';\n});\n\nqueue.add(async () => {\n console.log('कार्य 2 शुरू हुआ');\n return 'परिणाम 2';\n});\nयह उदाहरण बुनियादी यांत्रिकी को प्रदर्शित करता है: कार्यों को एक सरणी में जोड़ा जाता है और क्रम से निष्पादित किया जाता है। प्रत्येक कार्य एक Promise लौटाता है, जो परिणामों के साथ आसानी से काम करने की अनुमति देता है। हालाँकि, इस दृष्टिकोण की सीमाएँ हैं: प्राथमिकताओं, पुनः प्रयासों और एप्लिकेशन को पुनरारंभ करने पर स्थिति को संरक्षित करने का कोई समर्थन नहीं है।
\n\n2. प्राथमिकता और त्रुटि प्रबंधन
\nवास्तविक परियोजनाओं में, कार्यों का अक्सर अलग-अलग महत्व होता है। उदाहरण के लिए, एक लेन-देन संबंधी ईमेल भेजने का कार्य अस्थायी फ़ाइलों को साफ करने के कार्य से पहले किया जाना चाहिए। अपनी कतार में प्राथमिकताएँ जोड़ते हैं।
\ntype Priority = 'high' | 'medium' | 'low';\n\ninterface PriorityTask<T> {\n task: Task<T>;\n priority: Priority;\n resolve: (value: T) => void;\n reject: (reason?: any) => void;\n retries: number;\n}\n\nclass PriorityQueue {\n private high: PriorityTask<any>[] = [];\n private medium: PriorityTask<any>[] = [];\n private low: PriorityTask<any>[] = [];\n private isProcessing = false;\n private maxRetries = 3;\n\n add<T>(task: Task<T>, priority: Priority = 'medium'): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const taskItem: PriorityTask<T> = {\n task,\n priority,\n resolve,\n reject,\n retries: 0\n };\n this.getQueue(priority).push(taskItem);\n this.process();\n });\n }\n\n private getQueue(priority: Priority): PriorityTask<any>[] {\n switch (priority) {\n case 'high': return this.high;\n case 'medium': return this.medium;\n