समस्या: अतिरिक्त इंफ्रा-स्ट्रक्चर के बिना अनुसूचित काम\n\nज्यादातर ऐप्स को बाद में या शेड्यूल पर काम करना होता है: फॉलो‑अप ईमेल भेजना, हर रात बिलिंग चेक करना, पुराने रिकॉर्ड साफ़ करना, रिपोर्ट फिर से बनाना, या कैश रिफ्रेश करना।\n\nशुरू में यह भरसक लगेगा कि बैकग्राउंड जॉब्स के लिए पूरा queue सिस्टम लगा देना चाहिए। लेकिन queue एक और सेवा जोड़ता है: चलाना, मॉनिटर करना, डिप्लॉय और डिबग करना—छोटी टीम (या सोलो फाउंडर) के लिए यह बोझ काम धीमा कर सकता है।\n\nतो असली सवाल है: बिना अतिरिक्त इंफ्रा‑स्ट्रक्चर के, भरोसेमंद तरीके से शेड्यूल्ड काम कैसे चलाएं?\n\nएक आम पहला प्रयास सरल होता है: एक cron एंट्री जो किसी endpoint को हिट करे, और वह endpoint काम करे। यह तब तक सही है जब तक कि यह अचानक सही न रहे। जैसे ही आपके पास एक से अधिक सर्वर हों, गलत समय पर deploy हो, या कोई जॉब अपेक्षा से लंबा चल जाए, आप अजीब तरह की त्रुटियाँ देखना शुरू कर देंगे।\n\nअनुसूचित काम आमतौर पर कुछ पूर्वानुमेय तरीकों से टूटता है:\n\n- डबल रन: दो सर्वर एक ही टास्क चला देते हैं—इंवॉइस दो बार बनते हैं या ईमेल दो बार भेजे जाते हैं।\n- खोए रन: deploy के दौरान cron कॉल फेल हो जाती है और तब तक कोई नोटिस नहीं करता जब तक कि यूज़र शिकायत न करें।\n- साइलेंट फेल्यर: जॉब एक बार एरर देता है और फिर कभी नहीं चलता क्योंकि रीट्राई का कोई प्लान नहीं है।\n- आंशिक काम: जॉब बीच में क्रैश हो जाता है और डेटा अजीब स्थिति में रह जाता है।\n- कोई ऑडिट ट्रेल नहीं: आप नहीं बता सकते कि “यह आख़िरी बार कब चला?” या “कल रात क्या हुआ?”\n\ncron + database पैटर्न एक मध्य‑रास्ता है। आप अब भी cron का प्रयोग करते हैं ताकि शेड्यूल पर “जागना” हो, पर जॉब इरादा और स्थिति को डेटाबेस में स्टोर करते हैं ताकि सिस्टम समन्वय कर सके, रीट्राई कर सके, और क्या हुआ इसका रिकॉर्ड रखे।\n\nयह तब अच्छा बैठता है जब आपके पास पहले से एक डेटाबेस (आम तौर पर PostgreSQL) हो, जॉब प्रकारों की संख्या कम हो, और आप कम ऑप्स के साथ पूर्वानुमेय व्यवहार चाहें। यह आधुनिक स्टैक्स (उदा., React + Go + PostgreSQL) पर तेजी से बने ऐप्स के लिए भी प्राकृतिक विकल्प है।\n\nयह उस स्थिति में अच्छा नहीं है जहाँ आपको बहुत ऊँचा थ्रुपुट चाहिए, लंबी चलने वाली जॉब्स चाहिए जो प्रोग्रेस स्ट्रीम करें, कई जॉब प्रकारों के बीच सख्त ऑर्डरिंग हो, या भारी fan‑out (हज़ारों सब‑टास्क प्रति मिनट)। उन केसों में एक असली queue और समर्पित वर्कर बेहतर होते हैं।\n\n## सरल भाषा में मुख्य विचार\n\ncron + database पैटर्न शेड्यूल पर बैकग्राउंड काम चलाता है बिना पूरे queue सिस्टम के। आप cron (या कोई भी scheduler) का उपयोग जारी रखते हैं, पर cron यह तय नहीं करता कि क्या चलना चाहिए—बस वह वर्कर को अक्सर जगाता है (एक मिनट में एक बार सामान्य)। डेटाबेस तय करता है कौन सा काम देय है और यह सुनिश्चित करता है कि केवल एक वर्कर ही हर जॉब ले।\n\nइसे एक साझा चेकलिस्ट वाली व्हाइटबोर्ड की तरह सोचें। Cron हर मिनट कमरे में आता है और कहता है, “किसी को कुछ करना है?” डेटाबेस वही व्हाइटबोर्ड है जो दिखाता है क्या देय है, क्या पहले ही लिया जा चुका है, और क्या पूरा हो चुका है।\n\nघटक आसान हैं:\n\n- एक सरल scheduler trigger जो अक्सर चलता है।\n- एक jobs तालिका जो “क्या” और “कब” (due time), साथ में स्थिति और प्रयास‑गिनती रखती है।\n- एक या अधिक वर्कर तालिका को पोल करते हैं, जॉब क्लेम करते हैं, और काम करते हैं।\n- क्लेमिंग डेटाबेस लॉक का उपयोग करती है ताकि दो वर्कर एक ही रो न पकड़ें।\n- डेटाबेस यही स्रोत‑सत्य रहता है कि क्या चला, क्या फेल हुआ, और क्या रीट्राई होना चाहिए।\n\nउदाहरण: आप हर सुबह इनवॉयस रिमाइंडर भेजना चाहते हैं, हर 10 मिनट में कैश रिफ्रेश करना चाहते हैं, और रात को पुराने सत्र हटाना चाहते हैं। तीन अलग cron कमांड के बजाय (हर एक के अपने ओवरलैप और फेल्योर मोड होते हैं), आप जॉब एंट्रीज़ एक जगह स्टोर करते हैं। Cron वही वर्कर प्रोसेस शुरू करता है। वर्कर Postgres से पूछता है, “अब क्या देय है?” और Postgres सुरक्षित तरीके से वर्कर को एक‑एक कर के जॉब क्लेम करने देता है।\n\nयह धीरे‑धीरे स्केल करता है। आप एक सर्वर पर एक वर्कर से शुरू कर सकते हैं। बाद में आप कई सर्वरों पर पाँच वर्कर चला सकते हैं। समझौता वही रहता है: टेबल ही कंड्रैक्ट है।\n\nमाइंडसेट शिफ्ट सरल है: cron केवल वेक‑अप कॉल है। डेटाबेस ट्रैफ़िक‑कॉप है जो तय करता है क्या चलना चाहिए, क्या रिकॉर्ड हुआ, और जब कुछ गलत हो तो स्पष्ट इतिहास देता है।\n\n## jobs तालिका डिजाइन करना (व्यवहारिक स्कीमा)\n\nयह पैटर्न सबसे अच्छा तब काम करता है जब आपका डेटाबेस यह स्रोत‑सत्य हो कि क्या चलना चाहिए, कब चलना चाहिए, और पिछली बार क्या हुआ। स्कीमा खास नहीं है, पर छोटे‑छोटे विवरण (लॉक फ़ील्ड और सही इंडेक्स) लोड बढ़ने पर बहुत फर्क डालते हैं।\n\n### एक तालिका या दो?\n\nदो आम दृष्टिकोण:\n\n- जब आप केवल प्रत्येक जॉब की नवीनतम स्थिति पर ध्यान देते हैं (सरल, कम joins)।\n- जब आप “यह जॉब क्या है” और “हर बार यह कब चला” के बीच साफ़ अलगाव चाहते हैं (अच्छा इतिहास, डिबग करना आसान)।\n\nअगर आप अक्सर फेल्यर डिबग करने की उम्मीद करते हैं तो इतिहास रखें। सबसे छोटा सेटअप चाहिए तो एक तालिका से शुरू करें और बाद में इतिहास जोड़ें।\n\n### एक व्यवहारिक स्कीमा (दो‑तालिका वर्ज़न)\n\nयहाँ PostgreSQL‑फ्रेंडली लेआउट है। अगर आप Go + PostgreSQL में बना रहे हैं, ये कॉलम साफ़ structs से मैच करते हैं।\n\n\n\nकुछ विवरण जो बाद में दर्द बचाते हैं:\n\n- छोटा स्ट्रिंग रखें जिस पर आप राउट कर सकें (जैसे ).\n- को में रखें ताकि इसे माईग्रेशन के बिना विकसित किया जा सके।\n- आपका “next due time” है। Cron (या scheduler स्क्रिप्ट) इसे सेट करता है, वर्कर इसे consume करते हैं।\n- और वर्करों को बिना एक दूसरे को टकराए जॉब क्लेम करने देते हैं।\n- छोटा और मानव‑पठनीय रखें। स्टैक‑ट्रेस कहीं और रखें अगर जरूरत हो।\n\n### जरूरी इंडेक्स\n\nइंडेक्स के बिना वर्कर बहुत स्कैन कर देते हैं। शुरू में ये रखें:\n\n- देय काम जल्दी खोजने के लिए एक इंडेक्स: \n- एक्सपायर्ड लॉक पता करने में मदद करने वाला इंडेक्स: \n- वैकल्पिक: सक्रिय काम के लिए partial index (उदा., status और पर)\n\nये "find next runnable job" क्वेरी को तेज रखते हैं भले ही टेबल बड़ी हो जाए।\n\n## सुरक्षित तरीके से लॉक करना और जॉब क्लेम करना\n\nलक्ष्य सरल है: कई वर्कर चल सकते हैं, पर केवल एक ही किसी खास जॉब को ले। अगर दो वर्कर एक ही रो प्रोसेस कर लें, तो डबल ईमेल, डबल चार्ज या गंदा डेटा मिलता है।\n\nसुरक्षित तरीका यह है कि जॉब क्लेम को एक "लीज़" की तरह मानें। वर्कर जॉब को थोड़े समय के लिए लॉक कर देता है। अगर वर्कर क्रैश हो जाए, तो लीज़ एक्सपायर हो जाएगी और कोई और वर्कर उसे उठा सकेगा। यही कारण है मौजूद है।\n\n### क्रैश्स कभी काम को हमेशा के लिए ब्लॉक न करें — लीज़ का उपयोग करें\n\nयदि लीज़ न हो तो वर्कर जॉब लॉक करके कभी अनलॉक न कर पाए (प्रोसेस मारा गया, सर्वर रीबूट, deploy ग़लत)। के साथ, समय गुजरने पर जॉब फिर से उपलब्ध हो जाता है।\n\nएक सामान्य नियम: जब हो या हो तो जॉब क्लेम किया जा सकता है।\n\n### एक एटॉमिक अपडेट में जॉब क्लेम करें\n\nमुख्य बात यह है कि जॉब को एक ही स्टेटमेंट (या एक ट्रांज़ैक्शन) में क्लेम करें। आप चाहते हैं कि डेटाबेस रेफरी बने।\n\nयहाँ एक सामान्य PostgreSQL पैटर्न है: एक देय जॉब चुनें, लॉक करें, और उसे वर्कर को लौटाएँ। (यह उदाहरण एक टेबल उपयोग करता है; वही विचार पर भी लागू होता है।)\n\n\n\nक्यों यह काम करता है:\n\n- कई वर्कर को प्रतिस्पर्धा करने देता है बिना एक दूसरे को ब्लॉक किए।\n- लीज़ क्लेम के समय सेट होती है, इसलिए अन्य वर्कर तब तक उसे इग्नोर करते हैं जब तक वह एक्सपायर न हो।\n- उस वर्कर को रो सौंप देता है जिसने रेस जीत ली।\n\n### लीज़ कितनी लंबी होनी चाहिए, और इसे कैसे रीन्यू करें?\n\nलीज़ को सामान्य रन से लंबा रखें, पर इतना छोटा कि क्रैश जल्दी recover करे। अगर ज्यादातर जॉब 10 सेकंड में खत्म होते हैं, तो 2 मिनट की लीज़ काफी है।\n\nलंबी टास्क के लिए, काम करते समय लीज़ रीन्यू करें (हार्टबीट)। एक सरल तरीका: हर 30 सेकंड में बढ़ा दें अगर आप अब भी जॉब के मालिक हैं।\n\n- लीज़ लंबाई: आपके सामान्य जॉब समय की 5x से 20x\n- हार्टबीट अंतराल: लीज़ का 1/4 से 1/2\n- रीन्यू अपडेट में शामिल करें \n\nयह अंतिम शर्त महत्व रखती है—यह रोकती है कि कोई वर्कर ऐसे जॉब की लीज़ बढ़ा दे जो अब उसका नहीं रहा।\n\n## ऐसी रीट्राई और बैकऑफ जो अनुमान योग्य हों\n\nरीट्राई वहां हैं जहाँ यह पैटर्न शांत लगेगा या शोरगुल वाला हो जाएगा। लक्ष्य सरल है: जब जॉब फेल हो, तो बाद में फिर से कोशिश करें इस तरह कि आप समझा सकें, नाप सकें, और रोक सकें।\n\nराज्य स्पष्ट और सीमित रखकर शुरू करें: , , , , . व्यवहार में अधिकांश टीमें को "फेल हुआ पर रीट्राई होगा" और को "फेल हुआ और हम हार मान गए" के रूप में यूज़ करती हैं। यह एक अंतर अनंत लूप से बचाता है।\n\nप्रयास‑गिनती (attempt counting) दूसरा सुरक्षा घेरे है। (कितनी बार कोशिश की) और (कितनी बार अनुमति है) रखें। जब वर्कर कोई एरर पकड़े, उसे करना चाहिए:\n\n- बढ़ाएँ\n- अगर तो स्थिति रखें, अन्यथा \n- अगले ट्राय के लिए गणना करें (केवल के लिए)\n\nबैकऑफ बस नियम है जो अगले को तय करता है। एक चुनें, इसका डॉक्यूमेंट रखें, और सुसंगत रहें:\n\n- फिक्स्ड डिले: हमेशा 1 मिनट इंतज़ार\n- एक्सपोनेंशियल: 1m, 2m, 4m, 8m\n- कैप वाला एक्सपोनेंशियल: एक्सपोनेंशियल पर कभी अधिकतम, जैसे 30m तक\n- जिटर जोड़ें: थोड़ा रैंडमाइज़ करें ताकि सब जॉब एक ही सेकंड में रीट्राई न करें\n\nजब कोई निर्भरता डाउन हो और वापस आए तो जिटर मायने रखता है—बगैर जिटर के सैकड़ों जॉब एक साथ रीट्राई कर सकते हैं और फिर से फेल।\n\nफेल्यर को डिबग करने लायक पर्याप्त एरर डिटेल स्टोर करें। आपको पूरा लॉगिंग सिस्टम नहीं चाहिए, पर बेसिक्स चाहिए:\n\n- (छोटा मैसेज, admin स्क्रीन में दिखाने लायक)\n- या (ग्रोप करने में मदद)\n- और \n- वैकल्पिक (साइज़ कंट्रोल के साथ)\n\nएक ठोस नियम जो अच्छा काम करता है: 10 प्रयासों के बाद जॉब को मार्क करें, और एक्सपोनेंशियल बैकऑफ + जिटर रखें। यह ट्रांज़िएंट फेल्यर्स को रीट्राई करता है पर ब्रोकन जॉब्स को अनंत CPU जलाने से रोकता है।\n\n## Idempotency: दोहराने पर डुप्लिकेट रोकना\n\nIdempotency का अर्थ है कि आपकी जॉब दो बार चल जाए और अंतिम परिणाम वही रहे। इस पैटर्न में यह ज़रूरी है क्योंकि वही रो क्रैश, टाइमआउट, या रीट्राई के बाद फिर से उठ सकती है। अगर आपकी जॉब “इनवॉयस ईमेल भेजो” है, तो इसे दो बार चलाना हानिकारक हो सकता है।\n\nव्यावहारिक तरीके से सोचें: हर जॉब को (1) काम करना और (2) प्रभाव लागू करना—इन दो में बाँट दें। आप चाहते हैं कि प्रभाव केवल एक बार हो, भले ही काम कई बार ट्राय हो।\n\n### बिज़नेस इवेंट से जुड़ी idempotency key का उपयोग करें\n\nIdempotency key को उस चीज़ से लें जो जॉब प्रतिनिधित्व करती है, न कि वर्कर प्रयास से। अच्छे कीज़ स्थिर और समझने में आसान होते हैं, जैसे , , या . अगर दो जॉब प्रयास एक ही वास्तविक‑लौ‑इवेंट को रेफर करते हैं, तो उन्हें वही key मिली चाहिए।\n\nउदाहरण: “2026-01-14 के लिए दैनिक सेल्स रिपोर्ट जेनरेट करें” के लिए हो सकता है। “इंवॉयस 812 चार्ज करें” के लिए ।\n\n### डेटाबेस कंस्ट्रेंट से "केवल एक बार"-enforce करें\n\nसरलतम गार्डरेल PostgreSQL को डुप्जेक्ट्स रिजेक्ट करने देना है। idempotency key को कहीं स्टोर करें जिसे इंडेक्स किया जा सके, फिर unique constraint जोड़ें।\n\n\n\nयह एक ही key के साथ दो रो के अस्तित्व को रोकेगा। अगर आपका डिज़ाइन कई रो की इजाज़त देता है (इतिहास के लिए), तो uniqueness किसी “effects” टेबल पर रखें, जैसे या .\n\nकुछ आम साइड‑इफ़ेक्ट जिन्हें आप प्रोटेक्ट करना चाहेंगे:\n\n- ईमेल: भेजने से पहले में एक रो बनाएं जिसमें यूनिक की हो, या भेजने के बाद provider message id रिकॉर्ड करें।\n- वेबहुक: स्टोर करें और अगर मौजूद हो तो स्किप करें।\n- पेमेंट: हमेशा पेमेंट प्रोवाइडर की idempotency फीचर का उपयोग करें और अपनी डेटाबेस यूनिक की भी रखें।\n- फ़ाइल लेखन: टेम्प नाम पर लिखें, फिर रीनेम करें, या की पर एक रिकॉर्ड रखें।\n\nअगर आप Postgres‑बैक्ड स्टैक पर बना रहे हैं (उदा., Go + PostgreSQL), तो ये यूनिकनेस चेक तेज़ और डेटा के करीब रखे जा सकते हैं। मुख्य विचार सरल है: रीट्राई सामान्य है, डुप्लिकेट अनिवार्य नहीं।\n\n## स्टेप‑बाय‑स्टेप: एक न्यूनतम वर्कर और scheduler बनाना\n\nएक सरल runtime चुनें और उसी पर टिकें। cron + database पैटर्न का मतलब कम मूविंग पार्ट्स है, इसलिए एक छोटा Go, Node, या Python प्रोसेस जो PostgreSQL से बात करे सामान्यत: काफी होता है।\n\n### इसे पाँच छोटे कदमों में बनायें\n\n1) एक टेबल (और जो lookup टेबल आप बाद में चाहें) जोड़ें, फिर को इंडेक्स करें, और एक ऐसा इंडेक्स जोड़ें जो वर्कर को उपलब्ध जॉब जल्दी ढूँढने में मदद करे (उदा., )।\n\n2) आपका ऐप एक रो इंसर्ट करे जिसमें अभी या भविष्य में हो। payload छोटा और predictable रखें (IDs और job type, बड़े blobs न रखें)।\n\n\n\n3) इसे एक ट्रांज़ैक्शन में चलाएँ। कुछ देय जॉब चुनें, उन्हें लॉक करें ताकि अन्य वर्कर उन्हें स्किप करें, और उसी ट्रांज़ैक्शन में उन्हें मार्क करें।\n\n\n\n4) हर क्लेम किए गए जॉब के लिए काम करें, फिर के रूप में अपडेट करें और भरें। अगर फेल हो, तो एरर मैसेज रिकॉर्ड करें और के साथ फिर से में डालें। फाइनलाइज़ेशन अपडेट छोटे रखें और उन्हें हमेशा चलाएँ—even अगर प्रोसेस बंद हो रहा हो।\n\n5) एक सरल फ़ॉर्मूला लें जैसे , और के पार होने पर सेट कर दें।\n\n### बेसिक विजिबिलिटी जोड़ें\n\nपहले दिन एक पूरा डैशबोर्ड ज़रूरी नहीं है, पर समस्याएँ नोटिस करने के लिए पर्याप्त चीज़ें चाहिए।\n\n- हर जॉब के लिए एक लाइन लॉग करें: claimed, succeeded, failed, retried, dead।\n- “dead jobs” और “old running jobs” के लिए एक सरल admin क्वेरी/व्यू बनाएं।\n- failure counts पर अलर्ट रखें (उदा., पिछले घंटे में N से ज्यादा dead jobs)।\n\nअगर आप Go + PostgreSQL स्टैक पर हैं, तो यह एक सिंगल वर्कर बाइनरी + cron के रूप में आसानी से मैप हो जाता है।\n\n## आप कॉपी कर सकने वाला एक वास्तविक उदाहरण\n\nमान लीजिए एक छोटी SaaS ऐप में दो शेड्यूल्ड काम हैं:\n\n- एक nightly cleanup जो expired sessions और पुराने temp files हटाता है।\n- एक weekly “your activity report” ईमेल जो हर सोमवार सुबह हर यूज़र को भेजा जाता है।\n\nसरल रखें: जॉब्स को होल्ड करने के लिए एक PostgreSQL टेबल और हर मिनट चलने वाला एक वर्कर (cron द्वारा ट्रिगर)। वर्कर देय जॉब क्लेम करता है, उन्हें रन करता है, और सफलता या फेल्योर रिकॉर्ड करता है।\n\n### क्या enqueue होता है, और कब\n\nआप कुछ जगहों से जॉब enqueue कर सकते हैं:\n\n- रोज़ 02:00 पर: एक जॉब enqueue करें।\n- साइनअप पर: किसी यूज़र के अगले सोमवार के लिए enqueue करें।\n- किसी इवेंट के बाद (जैसे “user clicked Export report”): एक जॉब तुरंत enqueue करें जो एक स्पेसिफ़िक डेट‑रेंज के लिए चले।\n\nPayload सिर्फ़ वही रखें जो वर्कर को चाहिए। इसे छोटा रखें ताकि रीट्राई आसान हो।\n\n\n\n### कैसे idempotency डबल‑सेंड़ को रोकेगा\n\nसबसे खराब समय पर वर्कर क्रैश कर सकता है: ईमेल भेजने के ठीक बाद, पर जॉब को "done" मार्क करने से पहले। फिर जब वह फिर से शुरू होता है, तो वही जॉब दोबारा उठ सकता है।\n\nडबल‑सेंड रोकने के लिए, काम को एक नेचुरल डेडुप की दें और उसे डेटाबेस‑एन्फोर्सेबल जगह पर स्टोर करें। साप्ताहिक रिपोर्ट के लिए एक अच्छा की है। भेजने से पहले वर्कर रिकॉर्ड कर देता है “मैं रिपोर्ट X भेजने वाला हूँ”。यदि वह रिकॉर्ड पहले से मौजूद है तो स्किप कर दे।\n\nयह टेबल में पर यूनिक कंस्ट्रेंट की तरह सरल हो सकता है, या जॉब पर यूनिक भी हो सकता है।\n\n### एक फेल्यर कैसा दिखता है (और कैसे रिकवर होता है)\n\nमान लीजिए आपका ईमेल प्रोवाइडर टाइमआउट दे देता है। जॉब फेल हो जाती है, तो वर्कर:\n\n- बढ़ाता है\n- डिबग के लिए एरर मैसेज सेव करता है\n- बैकऑफ के साथ अगली कोशिश शेड्यूल करता है (उदा., +1 min, +5 min, +30 min, +2 hours)\n\nअगर यह आपकी लिमिट (जैसे 10 प्रयास) पार कर जाए तो उसे मार्क कर दें और रीट्राई रोक दें। जॉब या तो एक बार सफल होगी, या स्पष्ट शेड्यूल पर रीट्राई होती रहेगी—और idempotency रीट्राई को सुरक्षित बनाती है।\n\n## आम गलतियाँ और जाल\n\ncron + database पैटर्न सरल है, पर छोटी‑छोटी गलतियाँ इसे डुप्लिकेट, अटकी हुई वर्क, या आश्चर्यजनक लोड में बदल सकती हैं। ज्यादातर इश्यू पहले क्रैश, deploy, या ट्रैफ़िक स्पाइक के बाद दिखते हैं।\n\n### डुप्लिकेट या अटके जॉब्स पैदा करने वाली गलतियाँ\n\nकई वास्तविक घटनाएँ कुछ फंदों से आती हैं:\n\n- एक ही जॉब को कई cron एंट्रीज़ से चलाना बिना लीज़ के। अगर दो सर्वर एक ही मिनट पर टिक करें, तो दोनों एक ही काम क्लेम कर सकते हैं जब तक कि आपका क्लेम स्टेप एटॉमिक न हो और उसी ट्रांज़ैक्शन में लॉक (या लीज़) सेट न करे।\n- को न अपनाना। अगर वर्कर क्लेम करने के बाद क्रैश कर जाए, तो वह रो “in progress” के रूप में हमेशा के लिए रह सकती है। लीज़ टाइमस्टैम्प दूसरे वर्कर को सुरक्षित रूप से बाद में लेने देता है।\n- फेल्यर पर तुरंत रीट्राई करना। जब कोई API डाउन हो, तुरंत रीट्राई spikes बनाते हैं, rate limits जलाते हैं, और लगातार फेल होते रहते हैं। अगली कोशिश हमेशा भविष्य में शेड्यूल करें।\n- “at least once” को “exactly once” समझ लेना। जॉब दोबारा चल सकती है (टाइमआउट, वर्कर रीस्टार्ट, नेटवर्क इश्यू)। अगर दो बार चलना हानिकारक है, तो साइड‑इफ़ेक्ट को दोहराने‑सुरक्षित बनाएं।\n- जॉब रो में बड़ा payload स्टोर करना। बड़े JSON blobs टेबल को फुल कर देते हैं, इंडेक्स धीमे कर देते हैं, और लॉकिंग भारी बनाते हैं। एक संदर्भ (जैसे , , या फाइल की कुंजी) रखें और रन करते समय बाकी फेच करें।\n\nउदाहरण: आप साप्ताहिक इनवॉयस ईमेल भेजते हैं। अगर वर्कर ईमेल भेजने के बाद टाइमआउट हो जाए पर जॉब को "done" मार्क न करे, तो वही जॉब दोबारा चल सकती है और डुप्लीकेट ईमेल भेजे जा सकते हैं। यह पैटर्न के लिए सामान्य है जब तक आप गार्डरेल न जोड़ें (उदा., invoice id पर यूनिक "email sent" इवेंट रिकॉर्ड करना)।\n\n### कम स्पष्ट गोट्चाज़\n\nलंबी ट्रांज़ैक्शन में शेड्यूलिंग और एक्सेक्यूशन दोनों मिक्स करने से बचें। अगर आप नेटवर्क कॉल करते समय ट्रांज़ैक्शन खुली रखते हैं, तो आप लॉक्स को ज़रूरत से ज्यादा लंबे समय तक रखें और दूसरे वर्करों को ब्लॉक करें।\n\nमशीनों के बीच क्लॉक फ़र्क़ पर ध्यान दें। और के लिए डेटाबेस समय ( in PostgreSQL) को स्रोत‑सत्य मानें, न कि एप्लिकेशन सर्वर क्लॉक।\n\nएक स्पष्ट अधिकतम रनटाइम सेट करें। अगर कोई जॉब 30 मिनट ले सकती है, तो लीज़ को उससे लंबा रखें और आवश्यक हो तो रीन्यू करें। वरना कोई और वर्कर उसे बीच में उठा लेगा।\n\nअपनी जॉब टेबल को स्वस्थ रखें। अगर कम्प्लीटेड जॉब्स हमेशा के लिए इकट्ठे होते रहें तो क्वेरी धीमी होंगी और लॉक कंटेंशन बढ़ेगा। टेबल बहुत बड़ी होने से पहले एक रिटेंशन नियम (archive या delete) चुन लें।\n\n## त्वरित चेकलिस्ट और अगले कदम\n\n### त्वरित चेकलिस्ट\n\nइस पैटर्न को शिप करने से पहले मूल बातें जांच लें। यहाँ एक छोटी चूक आमतौर पर अटके जॉब, अप्रत्याशित डुप्लिकेट, या डेटाबेस पर जबरदस्त दबाव बनाती है।\n\n- आपकी jobs तालिका में ज़रूरी फ़ील्ड हों: , , , , और (साथ में या समान ताकि आप देख सकें क्या हुआ)।\n- हर जॉब सुरक्षित रूप से दो बार चल सकती है। अगर आप सुनिश्चित नहीं हैं, तो idempotency key जोड़ें या साइड‑इफ़ेक्ट पर यूनिकनी तय करें (उदा., पर एक‑हिंज)।\n- विफलताओं का निरीक्षण और निर्णय लेने की स्पष्ट जगह हो: failed jobs देखें, किसी जॉब को फिर से चलाएं, या जब इसे रोकना हो तो उसे dead मार्क करें।\n- आपकी लीज़ (लॉक) टाइमआउट काम के लिए ठीक हो—नियमित रन के लिए लंबा, पर क्रैश होने पर घंटों तक प्रगति ब्लॉक न करे।\n- रीट्राई बैकऑफ़ अनुमाननीय हो। यह बार‑बार फेल्यर को धीमा करना चाहिए और के बाद रोक देना चाहिए।\n\nयदि ये सच हैं, तो cron + database पैटर्न आम तौर पर असली वर्कलोड के लिए पर्याप्त स्थिर होता है।\n\n### अगले कदम\n\nचेकलिस्ट ठीक लगने पर, दिन‑प्रतिदिन के ऑपरेशन पर ध्यान दें।\n\n- दो छोटे admin एक्शन जोड़ें: “retry now” ( और लॉक साफ़ करें) और “cancel” (टर्मिनल स्थिति में ले जाएँ)। ये incidents में समय बचाते हैं।\n- वर्कर हर जॉब पर एक लाइन लॉग करे: job type, job id, attempt number, और result। failure counts पर अलर्ट जोड़ें।\n- वास्तविक स्पाइक के साथ लोड टेस्ट کریں: बहुत से जॉब एक ही मिनट के लिए शेड्यूल हों। अगर क्लेम करना धीमा होता है, तो सही इंडेक्स जोड़ें (आम तौर पर )।\n\nअगर आप इस तरह की सेटअप जल्दी बनाना चाहते हैं, तो Koder.ai (koder.ai) आपकी मदद कर सकता है कि स्कीमा से लेकर डिप्लॉय किए गए Go + PostgreSQL ऐप तक तेजी से पहुंचें, जबकि आप लॉकिंग, रीट्राई, और idempotency नियमों पर ध्यान दें।\n\nअगर आप बाद में इस सेटअप से बाहर निकलें, तो आपने जॉब लाइफसाइकल स्पष्ट रूप से सीखा होगा, और वही विचार किसी फुल‑क्यू सिस्टम में भी अच्छी तरह लागू होते हैं।