18 दिस॰ 2025·8 मिनट पढ़ने में

Cron की परेशानियों के बिना बैकग्राउंड जॉब शेड्यूल करना: पैटर्न

वर्कफ़्लो और jobs टेबल का उपयोग कर रिमाइंडर, दैनिक सारांश और क्लीनअप को विश्वसनीय तरीके से शेड्यूल करने के पैटर्न सीखें।

Cron की परेशानियों के बिना बैकग्राउंड जॉब शेड्यूल करना: पैटर्न

क्यों cron पहले सरल लगता है — और फिर नहीं

Cron पहले दिन में शानदार लगता है: एक लाइन लिखो, समय चुनो, भूल जाओ। एक सर्वर और एक टास्क के लिए यह अक्सर काम कर देता है।

समस्याएँ तब सामने आती हैं जब आप शेड्यूलिंग पर वास्तविक प्रोडक्ट व्यवहार भरोसा करते हैं: रिमाइंडर, दैनिक सारांश, क्लीनअप या सिंक जॉब्स। ज्यादातर “मिस्ड रन” कहानियाँ cron की विफलता नहीं होतीं। वे उसके चारों तरफ की चीज़ें होती हैं: सर्वर का रीबूट, deploy ने crontab ओवरराइट कर दिया, कोई जॉब उम्मीद से लंबा चल गया, या क्लॉक/टाइमज़ोन मेल नहीं खाया। और जब आप कई एप इंस्टेंसेज़ चलाते हैं, तो विपरीत विफलता मोड भी मिलता है: डुप्लीकेट्स, क्योंकि दो मशीनें एक ही काम चलाने की सोचती हैं।

टेस्टिंग भी कमजोर जगह है। एक cron लाइन आपको यह साफ़ तरीका नहीं देती कि "कल सुबह 9:00 पर क्या होगा" को दोहराने योग्य टेस्ट में कैसे चलाएं। इसलिए शेड्यूलिंग हाथ से चेक, प्रोडक्शन सरप्राइज़ और लॉग हंटिंग बन जाती है।

किसी तरीके को चुनने से पहले, स्पष्ट रहें कि आप क्या शेड्यूल कर रहे हैं। अधिकांश बैकग्राउंड काम कुछ बकेट्स में आता है:

  • रिमाइंडर (एक निश्चित समय पर, सिर्फ एक बार भेजना)
  • दैनिक सारांश (डेटा एग्रीगेट करके भेजना)
  • क्लीनअप टास्क (डिलीट, आर्काइव, एक्सपायर)
  • पीरियॉडिक सिंक (अपडेट्स पुश/पुल करना)

कभी-कभी आप शेड्यूलिंग पूरी तरह छोड़ भी सकते हैं। अगर कोई काम उसी इवेंट पर हो सकता है जब घटनाक्रम होता है (यूज़र साइनअप, पेमेंट सफल, टिकट स्टेटस बदला), तो इवेंट-ड्रिवन काम अक्सर समय-ड्रिवन काम से सरल और विश्वसनीय होता है।

जब आपको समय-आधारित काम चाहिए, तो भरोसा ज़्यादातर विज़िबिलिटी और कंट्रोल पर निर्भर करता है। आप एक ऐसी जगह चाहते हैं जहाँ रिकॉर्ड हो कि क्या चलना चाहिए, क्या चला, और क्या फेल हुआ — साथ ही दुहराव बिना सुरक्षित रीट्राइ करने का तरीका।

मूल पैटर्न: scheduler, jobs टेबल, worker

cron की परेशानियों से बचने का एक सरल तरीका ज़िम्मेदारियों को अलग करना है:

  • एक scheduler तय करता है कि क्या और कब चलना चाहिए।
  • एक worker वह काम करता है।

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

एक jobs टेबल सत्य का स्रोत बन जाती है। सर्वर प्रोसेस या cron लाइन के अंदर स्टेट छिपाने की बजाय, हर यूनिट ऑफ वर्क एक रो होती है: क्या करना है, किसके लिए है, कब चलना चाहिए, और पिछली बार क्या हुआ। जब कुछ गलत होता है, आप उसे निरीक्षण, रीट्राइ या रद्द कर सकते हैं बिना अनुमान लगाए।

एक साधारण फ्लो कुछ इस तरह दिखता है:

  • scheduler due jobs को स्कैन करता है (उदाहरण के लिए run_at <= now और status = queued).
  • यह किसी जॉब का क्लेम करता है ताकि सिर्फ़ एक worker उसे ले।
  • एक worker जॉब डिटेल्स पढ़कर कार्रवाई करता है।
  • worker वही रो अपडेट करके परिणाम रिकॉर्ड करता है।

मुख्य विचार यह है कि काम को जादुई नहीं बल्कि फिर से शुरू करने योग्य बनाएं। अगर worker आधा काम करके क्रैश हो जाए, तो जॉब रो आपको अभी भी बताना चाहिए कि क्या हुआ और अगला कदम क्या है।

ऐसी jobs टेबल डिज़ाइन करें जो उपयोगी रहे

एक jobs टेबल को जल्दी से दो सवालों का जवाब देना चाहिए: अगला क्या चलना है, और पिछली बार क्या हुआ।

पहले पहचान, समय और प्रोग्रेस को कवर करने वाले छोटे फील्ड्स से शुरू करें:

  • id, type: एक यूनिक id और एक छोटा प्रकार जैसे send_reminder या daily_summary
  • payload: वैलिडेटेड JSON जिसमें सिर्फ़ वही हो जो worker को चाहिए (उदा. user_id, पूरा यूज़र ऑब्जेक्ट नहीं)।
  • run_at: जब जॉब चलने के लिए एलिजिबल हो जाता है।
  • status: queued, running, succeeded, failed, canceled
  • attempts: हर कोशिश पर इंक्रीमेंट होता है।

फिर कुछ ऑपरेशनल कॉलम जोड़ें जो concurrency को सुरक्षित और incidents को हैंडल करना आसान बनाते हैं। locked_at, locked_by, और locked_until एक worker को जॉब क्लेम करने देते हैं ताकि आप उसे दो बार न चलाएँ। last_error छोटा संदेश होना चाहिए (और वैकल्पिक रूप से एक एरर कोड), पूरा स्टैक ट्रेस नहीं जो रो को ब्लो कर दे।

अंत में, सपोर्ट और रिपोर्टिंग में मदद करने वाले टाइमस्टैम्प रखें: created_at, updated_at, और finished_at। इससे आप पूछ सकते हैं “आज कितने रिमाइंडर फेल हुए?” बिना लॉग खोदे।

इंडेक्स मायने रखते हैं क्योंकि सिस्टम बार-बार पूछता है “अगला क्या है?” दो इंडेक्स अक्सर उपयोगी होते हैं:

  • (status, run_at) ताकि due jobs तेजी से फेच हों
  • (type, status) ताकि किसी जॉब फैमिली को इंस्पेक्ट या पाज़ किया जा सके

payloads के लिए, छोटे, फोकस्ड JSON को प्राथमिकता दें और जॉब डालने से पहले वैलिडेट करें। पहचानकर्ता और पैरामीटर्स स्टोर करें, बिजनेस डेटा के स्नैपशॉट नहीं। payload शेप को एक API कॉन्ट्रैक्ट की तरह ट्रीट करें ताकि पुराने queue किए जॉब्स आपके ऐप बदलने पर भी चल सकें।

जॉब लाइफसाइकल: स्टेटस, लॉकिंग और आइडेम्पोटेंसी

जब हर जॉब एक छोटे, अनुमानित लाइफसाइकल का पालन करे तो जॉब रनर भरोसेमंद रहता है। यह लाइफसाइकल आपकी सुरक्षा जाली है जब दो workers एक साथ शुरू हों, सर्वर बीच में रीस्टार्ट हो, या आपको बिना डुप्लिकेट के रीट्राइ करना हो।

एक सरल स्टेट मशीन अक्सर काफी होती है:

  • queued: run_at पर या उसके बाद रन करने के लिए तैयार
  • running: किसी worker ने क्लेम कर लिया
  • succeeded: पूरा हो गया और फिर नहीं चलना चाहिए
  • failed: एरर के साथ खत्म हुआ और ध्यान चाहिए
  • canceled: जानबूझकर रोका गया (उदा. यूज़र ने ऑप्ट-आउट किया)

डबल काम से बिना रोकथाम के जॉब्स क्लेम करना

डुप्लीकेट्स रोकने के लिए, जॉब क्लेम करना एटॉमिक होना चाहिए। सामान्य तरीका है टाइम-आधारित लॉक (लीज़): worker status=running सेट करके और locked_by तथा locked_until लिखकर जॉब क्लेम करता है। अगर worker क्रैश कर जाए, लॉक एक्सपायर हो जाता है और दूसरा worker उसे री-क्लेम कर सकता है।

एक व्यावहारिक क्लेमिंग नियम सेट:

  • सिर्फ queued जॉब्स ही क्लेम करें जिनका run_at <= now हो
  • status, locked_by, और locked_until को एक ही अपडेट में सेट करें
  • running जॉब्स तभी री-क्लेम करें जब locked_until < now हो
  • लीज़ को छोटा रखें और लंबी जॉब पर इसे एक्सटेंड करें

आइडेम्पोटेंसी (अच्छी आदत जो बचाती है)

आइडेम्पोटेंसी का मतलब: अगर वही जॉब दो बार चले, तो परिणाम सही ही रहे।

सबसे सरल टूल है एक यूनिक की। उदाहरण के लिए, दैनिक सारांश के लिए आप प्रतिदिन प्रति यूज़र एक जॉब लागू कर सकते हैं, जैसे summary:user123:2026-01-25। अगर डुप्लिकेट insert हो, तो वह दूसरी जॉब नहीं बनाएगा बल्कि उसी जॉब की ओर इशारा करेगा।

सफलता तभी मार्क करें जब साइड इफेक्ट असल में पूरा हो (ईमेल भेजा गया, रिकॉर्ड अपडेट हुआ)। अगर आप रीट्राइ करें, तो रीट्राइ पथ किसी दूसरे ईमेल या डुप्लिकेट राइट को पैदा न करे।

बिना नाटक के रीट्राइ और फेलियर हैंडलिंग

क्यू दृश्यता जल्दी पाएं
क्यू में queued, running, failed जॉब्स को फ़िल्टर करने और सुरक्षित रूप से पुनः चलाने के लिए एक एडमिन व्यू बनाएं।
एडमिन बनाएं

रीट्राइज़ वो जगह हैं जहाँ जॉब सिस्टम या तो भरोसेमंद बनते हैं या शोर उड़ाते हैं। लक्ष्य साधारण है: तब रीट्राइ करें जब फेलियर अस्थायी लगे, और तब बंद करें जब नहीं।

एक डिफ़ॉल्ट रीट्राइ पॉलिसी आमतौर पर शामिल करती है:

  • अधिकतम प्रयास (उदा. कुल 5 कोशिशें)
  • देरी की रणनीति (फिक्स्ड डिले या एक्सपोनेंशियल बैकऑफ)
  • रोकने की शर्तें ("invalid input" प्रकार की त्रुटियों पर रीट्राइ न करें)
  • जिटर (छोटा रैंडम ऑफ़सेट ताकि retry स्पाइक्स न हों)

रीट्राइ के लिए अलग स्टेटस बनाने की बजाय, अक्सर आप queued ही पुन: उपयोग कर सकते हैं: run_at को अगले प्रयास के समय पर सेट करके जॉब को वापस क्यू में डाल दें। इससे स्टेट मशीन छोटी रहती है।

जब जॉब आंशिक प्रोग्रेस कर सकता है, तो उसे सामान्य समझें। एक चेकपॉइंट स्टोर करें ताकि रीट्राइ सुरक्षित रूप से जारी रह सके — या तो जॉब payload में (जैसे last_processed_id) या एक संबंधित टेबल में।

उदाहरण: एक दैनिक सारांश जॉब 500 यूज़र्स के लिए संदेश बनाता है। अगर यह यूज़र 320 पर फेल हो जाता है, तो आख़िरी सफल यूज़र ID स्टोर करें और 321 से रीट्राइ करें। अगर आप प्रति यूज़र per-day summary_sent रिकॉर्ड भी स्टोर करते हैं, तो एक rerun पहले से किए हुए यूज़र्स को स्किप कर सकता है।

उपयोगी लॉगिंग

ऐसा लॉग करें जिससे आप मिनटों में डिबग कर सकें:

  • जॉब id, type और attempt नंबर
  • प्रमुख इनपुट्स (user/team id, date range)
  • समय (started_at, finished_at, next run time)
  • छोटा एरर सारांश (यदि उपलब्ध हो तो स्टैक ट्रेस)
  • साइड इफेक्ट्स की गिनती (ईमेल भेजे गए, पंक्तियाँ अपडेट हुई)

चरण-दर-चरण: एक साधारण scheduler लूप बनाना

फेलियर को बिना ड्रामा के संभालें
अपने जॉब वर्कफ़्लो में attempts, बैकऑफ टाइमिंग और स्टॉप कंडीशंस का उपयोग करें।
रीट्राइ जोड़ें

एक scheduler लूप एक छोटा प्रोसेस है जो फिक्स्ड ताल पर उठता है, due work खोजता है, और उसे हैंडऑफ़ करता है। लक्ष्य उबाऊ विश्वसनीयता है, न कि परफेक्ट टाइमिंग। कई ऐप्स के लिए "हर मिनट उठो" काफी होता है।

अपने जागने की आवृत्ति इस पर आधारित रखें कि जॉब्स कितने टाइम-सेंसिटिव हैं और आपका डेटाबेस कितना लोड सह सकता है। अगर रिमाइंडर लगभग रीयल-टाइम होना चाहिए, तो हर 30–60 सेकंड चलाएँ। अगर दैनिक सारांश थोड़ा डिफ्ट कर सकता है, तो हर 5 मिनट पर चलाना ठीक और सस्ता है।

एक सरल लूप:

  1. जागो और वर्तमान समय लो (UTC का उपयोग करें)।
  2. status = 'queued' और run_at <= now वाले due jobs चुनें।
  3. जॉब्स को सुरक्षित रूप से क्लेम करें ताकि सिर्फ़ एक worker उन्हें ले।
  4. हर क्लेम किए गए जॉब को worker को सौंपें।
  5. अगले टिक तक सोएं।

क्लेम स्टेप वह जगह है जहाँ कई सिस्टम टूटते हैं। आप एक ही ट्रांज़ैक्शन में जॉब को running मार्क करना और locked_by / locked_until लिखना चाहते हैं। कई डेटाबेस "skip locked" पढ़ने का समर्थन करते हैं ताकि कई schedulers बिना टकराए चल सकें।

-- concept example
BEGIN;
SELECT id FROM jobs
WHERE status='queued' AND run_at <= NOW()
ORDER BY run_at
LIMIT 100
FOR UPDATE SKIP LOCKED;
UPDATE jobs
SET status='running', locked_until=NOW() + INTERVAL '5 minutes'
WHERE id IN (...);
COMMIT;

बैच साइज छोटा रखें (जैसे 50–200)। बड़े बैच डेटाबेस को धीमा कर सकते हैं और क्रैश होने पर दर्दनाक बनाते हैं।

अगर scheduler बीच में क्रैश हो जाए, तो लीज़ आपकी सुरक्षा है। running में अटकी जॉब्स locked_until के बाद फिर से एलिजिबल बन जाती हैं। आपका worker आइडेम्पोटेंट होना चाहिए ताकि री-क्लेम की गई जॉब डुप्लिकेट ईमेल या डबल चार्ज न करे।

रिमाइंडर, दैनिक सारांश और क्लीनअप के पैटर्न

अधिकांश टीमें अंततः उन्हीं तीन प्रकार के बैकग्राउंड काम के साथ काम करती हैं: समय पर भेजे जाने वाले संदेश, शेड्यूल पर चलने वाले रिपोर्ट और स्टोरेज/परफॉर्मेंस को स्वस्थ रखने वाला क्लीनअप। वही jobs टेबल और worker लूप इन सबको संभाल सकते हैं।

रिमाइंडर

रिमाइंडर के लिए, जॉब रो में वह सब कुछ स्टोर करें जो मैसेज भेजने के लिए चाहिए: किसके लिए है, कौन सा चैनल (email, SMS, Telegram, इन-एप), कौन सा टेम्पलेट और सटीक भेजने का समय। worker को बिना "चारों तरफ देखने" के जॉब चलाने में सक्षम होना चाहिए।

अगर एक साथ कई रिमाइंडर ड्यू हैं, तो रेट-लिमिटिंग जोड़ें। प्रति मिनट प्रति चैनल मैसेज की सीमा लगाएँ और अतिरिक्त जॉब्स को अगले रन के लिए इंतज़ार करने दें।

दैनिक सारांश

दैनिक सारांश तब फेल होते हैं जब टाइम विंडो धुमिल हो। एक स्थिर कटऑफ समय चुनें (उदा. यूज़र के लोकल समय में 08:00), और विंडो को स्पष्ट रूप से परिभाषित करें (उदा. "कल 08:00 से आज 08:00")। रिरन्स में समान परिणाम हो, इसके लिए कटऑफ और यूज़र टाइमज़ोन जॉब के साथ स्टोर करें।

हर सारांश जॉब को छोटा रखें। अगर इसे हजारों रिकॉर्ड प्रोसेस करने हैं, तो उसे चंक्स में विभाजित करें (टीम के हिसाब से, अकाउंट के हिसाब से या ID रेंज से) और फॉलो-अप जॉब्स एंक्यू करें।

क्लीनअप टास्क

क्लीनअप तब सुरक्षित रहता है जब आप "डिलीट" और "आर्काइव" अलग रखें। तय करें क्या हमेशा के लिए हटाया जा सकता है (टेम्परेरी टोकन, एक्सपायर्ड सेशंस) और क्या आर्काइव करना चाहिए (ऑडिट लॉग, इनवॉइस)। क्लीनअप को प्रेडिक्टेबल बैचेस में चलाएँ ताकि लंबे लॉक और अचानक लोड स्पाइक्स न हों।

समय और टाइमज़ोन: बग्स का छुपा स्रोत

दैनिक सारांश ऑटोमेट करें
स्पष्ट समय विंडो और स्टोर किए गए यूजर टाइमज़ोन के साथ दैनिक सारांश शेड्यूल करें।
सारांश बनाएं

कई विफलताएँ टाइम बग्स से होती हैं: रिमाइंडर एक घंटा पहले चला जाता है, दैनिक सारांश सोमवार छूट जाता है, या क्लीनअप दो बार चल जाता है।

एक अच्छा डिफ़ॉल्ट है: शेड्यूल टाइमस्टैम्प UTC में स्टोर करें और यूज़र का टाइमज़ोन अलग स्टोर करें। आपका run_at एक UTC मोमेंट होना चाहिए। जब यूज़र कहे "मेरा समय में सुबह 9:00", तो शेड्यूल करते समय उसे UTC में कन्वर्ट करें।

डेलाईलाइट सेविंग टाइम वहीं है जहाँ साधारण सेटअप टूटते हैं। "हर दिन सुबह 9:00" और "हर 24 घंटे" एक ही बात नहीं हैं। DST शिफ्ट पर, सुबह 9:00 अलग UTC टाइम से मैप होगा, और कुछ लोकल टाइम्स मौजूद नहीं होते (spring forward) या दो बार होते हैं (fall back)। सुरक्षित तरीका यह है कि आप हर बार अगले लोकल ऑकरेन्स की गणना कर के उसे UTC में बदलें।

दैनिक सारांश के लिए, यह तय करें कि "एक दिन" का क्या मतलब है। कैलेंडर डे (यूज़र के टाइमज़ोन में आधी रात से आधी रात) मानवीय अपेक्षाओं से मेल खाता है। "पिछले 24 घंटे" सरल है पर डिफ्ट करता है और लोगों को चौंका सकता है।

लेट डेटा अटल है: कोई इवेंट देरी से आता है या आधी रात के बाद नोट जोड़ा जाता है। तय करें कि लेट इवेंट्स "कल" के भीतर आते हैं (एक ग्रेस पीरियड के साथ) या "आज" में, और उस नियम को स्थिर रखें।

एक व्यावहारिक बफ़र मिस होने से बचाता है:

  • 2–5 मिनट पहले तक के due jobs के लिए स्कैन करें
  • जॉब को आइडेम्पोटेंट रखें ताकि री-रन सुरक्षित हो
  • payload में कवर किए गए टाइम रेंज रिकॉर्ड करें ताकि सारांश स्थिर रहें

सामान्य गलतियाँ जो मिस्ड या डुप्लिकेट रन का कारण बनती हैं

अधिकतर दर्द कुछ अनुमानित धारणाओं से आता है।

सबसे बड़ी धारणा है "एक्सैक्टली-वन" एक्जीक्यूशन। असली सिस्टम में workers रीस्टार्ट होते हैं, नेटवर्क कॉल टाइमआउट करते हैं, और लॉक खो सकते हैं। आप सामान्यतः "अट-लीस्ट-वन" डिलीवरी पाते हैं, जिसका मतलब है कि डुप्लीकेट्स सामान्य हैं और आपका कोड उन्हें सहन कर सके।

एक और गलत धारणा है साइड-इफेक्ट्स पहले कर देना (ईमेल भेजना, कार्ड चार्ज करना) बिना डुप्लिकेट जांच के। एक साधारण गार्ड अक्सर समस्या हल कर देता है: sent_at टाइमस्टैम्प, (user_id, reminder_type, date) जैसा यूनिक की, या एक स्टोर किया हुआ डेड्यूप टोकन।

विज़िबिलिटी अगला गैप है। अगर आप नहीं बता सकते कि "क्या अटका हुआ है, कब से, और क्यों", तो आप अनुमान लगाने लगेंगे। नज़दीक रखने के लिए न्यूनतम डाटा है: status, attempt count, next scheduled time, last error, और worker id।

अक्सर दिखने वाली गलतियाँ:

  • जॉब्स को ऐसा डिज़ाइन करना मानकर कि वे ठीक-ठाक एक बार ही चलेंगे, और फिर डुप्लीकेट पर हैरान होना
  • साइड-इफेक्ट बिना डेड्यूप चेक के लिखना
  • एक बड़ा जॉब जिसमें सब कुछ करने की कोशिश करना और बीच में टाइमआउट का शिकार होना
  • अनंत तक रीट्राइ करना बिना कैप के
  • बेसिक क्यू विज़िबिलिटी स्किप करना (बैकलॉग, फेलियर्स, लंबी रनिंग आइटम्स की स्पष्ट छवि न होना)

एक ठोस उदाहरण: एक दैनिक सारांश जॉब 50,000 यूज़र्स पर लूप करता है और 20,000 यूज़र पर टाइमआउट हो जाता है। रीट्राइ पर, यह फिर से शुरुआत से चलना शुरू कर देगा और पहले 20,000 यूज़र्स को दोबारा सारांश भेज देगा जब तक आप प्रति-यूज़र पूरा होने का रिकॉर्ड न रखते या इसे प्रति-यूज़र जॉब्स में न बाँटें।

विश्वसनीय जॉब सिस्टम के लिए त्वरित चेकलिस्ट

अपने इन्फ्रास्ट्रक्चर पर जॉब्स चलाएँ
जब आप तैयार हों तो अपने scheduler और workers को अपने क्लाउड सेटअप पर डिप्लॉय करें।
ऐप डिप्लॉय करें

एक जॉब रनर "डन" तभी होता है जब आप इसे 2 बजे रात भरोसा कर सकें।

सुनिश्चित करें कि आपके पास है:

  • क्यू विज़िबिलिटी: queued बनाम running बनाम failed की गिनती, साथ में सबसे पुरानी queued जॉब।
  • डिफ़ॉल्ट रूप से आइडेम्पोटेंसी: मान लें हर जॉब दो बार चल सकता है; यूनिक कीज़ या "पहले से प्रोसेस्ड" मार्कर का उपयोग करें।
  • प्रति जॉब टाइप retry पॉलिसी: रीट्राइ, बैकऑफ, और स्पष्ट स्टॉप कंडीशन।
  • संगत समय संग्रहण: run_at UTC में रखें; केवल इनपुट और डिस्प्ले पर कन्वर्ट करें।
  • रिकवरएबल लॉक: एक लीज़ ताकि क्रैश होने पर जॉब्स हमेशा रनिंग में न अटकें।

साथ ही बैच साइज (एक बार में कितने जॉब आप क्लेम करते हैं) और worker concurrency (एक साथ कितने चलते हैं) को कैप करें। बिना कैप के, एक स्पाइक आपका डेटाबेस ओवरलोड कर सकता है या अन्य काम को_STARVE_ कर सकता है।

एक वास्तविक उदाहरण: छोटे टीम के लिए रिमाइंडर और सारांश

विश्वसनीय शेड्यूल किए गए टास्क बनाएं
ऐसे Business Processes बनाएं जिनमें scheduler और worker प्रक्रियाएँ हों जिन्हें आप सुरक्षित रूप से देख और बदल सकें।
शुरू करें

एक छोटा SaaS टूल है जिसमें 30 कस्टमर अकाउंट हैं। हर अकाउंट दो चीजें चाहता है: सुबह 9:00 पर किसी भी खुला काम के लिए रिमाइंडर, और शाम 6:00 पर उस दिन क्या बदला उसका दैनिक सारांश। उन्हें साप्ताहिक क्लीनअप भी चाहिए ताकि पुरानी लॉग और एक्सपायर्ड टोकन DB भर न दें।

वे jobs टेबल और एक worker का उपयोग करते हैं जो due जॉब्स के लिए पोल करता है। जब नया कस्टमर साइन अप करता है, बैकएंड उसके टाइमज़ोन के आधार पर पहला रिमाइंडर और सारांश शेड्यूल कर देता है।

जॉब्स कुछ सामान्य पलों पर बनते हैं: signup पर (recurring शेड्यूल बनाना), कुछ इवेंट्स पर (one-off नोटिफिकेशन enqueue करना), शेड्यूल टिक पर (आगामी रन insert करना), और मेंटेनेंस दिन पर (क्लीनअप एन्क्यू करना)।

एक मंगलवार, ईमेल प्रोवाइडर का अस्थायी आउटेज 8:59 AM पर हुआ। worker रिमाइंडर भेजने की कोशिश करता है, टाइमआउट मिलता है, और उन जॉब्स को बैकऑफ के अनुसार रिस्केड्यूल कर देता है (उदा. 2 मिनट, फिर 10, फिर 30), attempts हर बार बढ़ते जाते हैं। क्योंकि हर रिमाइंडर जॉब में account_id + date + job_type जैसा आइडेम्पोटेंसी की होता है, रीट्राइज़ के बीच प्रोवाइडर ठीक होने पर डुप्लिकेट नहीं बनते।

क्लीनअप छोटे बैचों में साप्ताहिक चलता है ताकि यह अन्य कामों को ब्लॉक न करे। एक मिलियन रो एक बार में डिलीट करने के बजाय, यह प्रति रन N रो हटाता है और जब तक खत्म न हो जाए खुद को फिर से शेड्यूल करता है।

जब कोई कस्टमर शिकायत करे "मुझे मेरा सारांश नहीं मिला", टीम उस अकाउंट और दिन के लिए jobs टेबल चेक करती है: जॉब स्टेटस, attempts काउंट, वर्तमान लॉक फील्ड्स, और प्रदाता द्वारा लौटाया गया last error। इससे "यह भेजा जाना चाहिए था" सवाल बदलकर "यहाँ क्या हुआ" बन जाता है।

अगले कदम: इम्प्लीमेंट करें, ऑब्जर्व करें, फिर स्केल करें

एक जॉब टाइप चुनें और उसे end-to-end बनाएं फिर और जोड़ें। एक सिंगल रिमाइंडर जॉब अच्छा स्टार्टिंग पॉइंट है क्योंकि यह सारी चीज़ों को छूता है: शेड्यूलिंग, क्लेम करना, मैसेज भेजना, और नतीजे रिकॉर्ड करना।

एक ऐसी वर्शन से शुरू करें जिस पर आप भरोसा कर सकें:

  • jobs टेबल और एक worker बनाएं जो एक जॉब टाइप प्रोसेस करे
  • एक scheduler लूप जोड़ें जो due जॉब्स क्लेम करे और चलाए
  • पर्याप्त payload स्टोर करें ताकि जॉब बिना अनुमान के चले
  • हर कोशिश और परिणाम को लॉग करें ताकि "क्या यह चला?" दस सेकंड का सवाल बन जाए
  • failed जॉब्स के लिए मैन्युअल rerun पाथ जोड़ें ताकि रिकवरी में deploy की ज़रूरत न पड़े

एक बार चलने पर, इसे मानवीय रूप से ऑब्ज़र्भेबल बनाएं। एक बेसिक एडमिन व्यू जल्दी ही फ़ायदा देता है: स्टेटस के हिसाब से जॉब्स सर्च करें, टाइम से फ़िल्टर करें, payload इंस्पेक्ट करें, अटकी जॉब कैंसिल करें, या किसी खास जॉब id को फिर से चलाएँ।

यदि आप इस तरह का scheduler और worker फ्लो विज़ुअल बैकएंड लॉजिक के साथ बनाना पसंद करते हैं, तो AppMaster (appmaster.io) jobs टेबल को PostgreSQL में मॉडल कर सकता है और claim-process-update लूप को Business Process के रूप में इम्प्लीमेंट कर सकता है, साथ ही डिप्लॉयमेंट के लिए वास्तविक सोर्स कोड भी जेनरेट करता है।

शुरू करना आसान
कुछ बनाएं अद्भुत

फ्री प्लान के साथ ऐपमास्टर के साथ प्रयोग करें।
जब आप तैयार होंगे तब आप उचित सदस्यता चुन सकते हैं।

शुरू हो जाओ