प्रॉम्प्ट और स्कोप
एक मल्टी-टेनेंट डिस्ट्रीब्यूटेड जॉब शेड्यूलर डिज़ाइन करें। यह वन-टाइम जॉब्स और IANA टाइम ज़ोन वाले क्रॉन जॉब्स का समर्थन करता है, 20 मिलियन एक्टिव शेड्यूल्स स्टोर करता है, प्रतिदिन 200 मिलियन ऑकरेंस बनाता है, और घंटे की शुरुआत में 500,000 ट्रिगर्स हो सकते हैं। सामान्य पीक लोड के तहत, सख्त (strict) जॉब्स को p99 पर उनके शेड्यूल्ड समय के 5 सेकंड के भीतर एक ड्यूरेबल कतार (queue) तक पहुँचना चाहिए। जिन जॉब्स को सटीक समय की आवश्यकता नहीं होती है, उन्हें 5 मिनट की फ्लेक्सिबल विंडो में फैलाया जा सकता है।
API शेड्यूल्स को बनाने, पॉज़ करने, रिज़्यूम करने, अपडेट करने और कैंसिल करने का समर्थन करता है। डिलीवरी एट-लीस्ट-वन्स है। शेड्यूलर शेड्यूल्ड समय को एक ऑकरेंस में बदलने और इसे एक टारगेट कतार में रखने के लिए ज़िम्मेदार है। कंटेनर प्लेसमेंट, DAG डिपेंडेंसीज़ और मनमाना वर्कफ़्लो ऑर्केस्ट्रेशन स्कोप से बाहर हैं। वास्तविक टास्क पूरा होने का समय 5-सेकंड शेड्यूलिंग SLO का हिस्सा नहीं है।
यह प्रश्न मिड-टू-सीनियर बैकएंड, प्लेटफ़ॉर्म, इन्फ्रास्ट्रक्चर और सिस्टम डिज़ाइन भूमिकाओं के लिए उपयुक्त है। 2026 की सार्वजनिक सिस्टम डिज़ाइन सामग्री अभी भी जॉब शेड्यूलर को एक स्टैंडअलोन इंटरव्यू समस्या के रूप में मानती है, जबकि वर्तमान AWS और Kubernetes दस्तावेज़ फ्लेक्सिबल विंडो, डुप्लिकेट या मिसिंग क्रिएशन, मिसफायर्स, टाइम ज़ोन और रिट्राइज़ के आसपास व्यावहारिक सीमाओं को उजागर करते हैं। मुख्य चुनौती क्रॉन को पार्स करना नहीं है। यह एक शेड्यूल्ड समय को एक ट्रेस करने योग्य, पुनः प्रयास करने योग्य (retryable), इडेम्पोटेंट निष्पादन में मज़बूती से बदलना (materialize करना) है।
इंटरव्यूअर क्या मूल्यांकन करता है
पहला संकेत Schedule, Occurrence, और Attempt को अलग करना है। एक शेड्यूल भविष्य के समय का वर्णन करता है। एक ऑकरेंस एक विशिष्ट शेड्यूल्ड समय का प्रतिनिधित्व करता है। एक प्रयास उस ऑकरेंस के लिए एक डिलीवरी या प्रोसेसिंग प्रयास का प्रतिनिधित्व करता है। next_run_at और status वाली एक एकल पंक्ति रिट्राइज़, इतिहास, अपडेट और अगले ट्रिगर को आपस में मिला देती है।
दूसरा संकेत सरसरी तौर पर एग्ज़ैक्टली-वन्स का वादा करने से इंकार करना है। एक शेड्यूलर एनक्यू (enqueue) करने के बाद लेकिन सफलता रिकॉर्ड करने से पहले क्रैश हो सकता है, और एक वर्कर अपनी पावती (acknowledgment) खोने से पहले एक साइड इफेक्ट पूरा कर सकता है। Kubernetes स्पष्ट रूप से नोट करता है कि एक CronJob कभी-कभी दो Jobs या कोई Job नहीं बना सकता है और इसलिए इडेम्पोटेंट जॉब्स की अनुशंसा करता है। एक मानक कतार का विज़िबिलिटी लीज़ भी डुप्लिकेट डिलीवरी को पूरी तरह से नहीं रोक सकता है। एक मज़बूत उत्तर एट-लीस्ट-वन्स डिलीवरी चुनता है और एक स्थिर ऑकरेंस ID के साथ व्यावसायिक प्रभाव को इडेम्पोटेंट बनाता है।
तीसरा संकेत सिंक्रोनाइज़्ड पीक्स को हैंडल करना है। दैनिक औसत केवल लगभग 2,315 ऑकरेंस प्रति सेकंड है, लेकिन 5 सेकंड के भीतर कतारों पर 500,000 स्ट्रिक्ट ट्रिगर्स रखने के लिए लगभग 100,000 डिस्पैच प्रति सेकंड की आवश्यकता होती है। औसत पर आधारित क्षमता घंटे की शुरुआत में विफल हो जाती है। एक ग्लोबल टाइम-ऑर्डर्ड हीप भी क्षमता और उपलब्धता का हॉट स्पॉट बनाता है।
अंत में, समय और विफलता का व्यवहार एक उत्पाद अनुबंध (product contract) होना चाहिए: क्या क्रॉन का अर्थ स्थानीय वॉल-क्लॉक समय है या एक निश्चित अंतराल, गैर-मौजूद और दोहराए गए डेलाइट-सेविंग समय का क्या होता है, क्या दस मिनट का आउटेज कैच-अप का कारण बनता है या स्किप करता है, क्या निष्पादन ओवरलैप हो सकते हैं, और एक ऑकरेंस के कतारबद्ध होने के बाद अपडेट या कैंसलेशन का क्या अर्थ है।
स्पष्ट करने के लिए प्रश्न
- पाँच सेकंड क्या मापता है? इसे केवल शेड्यूलिंग और एनक्यूइंग को कवर करते हुए
enqueued_at - scheduled_forके रूप में परिभाषित करें। यदि पूरा होना आवश्यक है, तो क्षमता मॉडल पूरी तरह से बदल जाता है। - क्या वन-टाइम, क्रॉन और फ़िक्स्ड-रेट शेड्यूल्स सभी आवश्यक हैं? यह डिज़ाइन वन-टाइम और क्रॉन का समर्थन करता है। प्रत्येक 24 घंटे डेलाइट-सेविंग परिवर्तनों में स्थानीय समय के 09:00 से भिन्न होते हैं और उन्हें समान गणना का उपयोग नहीं करना चाहिए।
- क्या चूक की तुलना में डुप्लिकेट बेहतर हैं? यह डिज़ाइन एट-लीस्ट-वन्स डिलीवरी चुनता है और इडेम्पोटेंसी के साथ डुप्लिकेट को संभालता है। एक गैर-दोहराए जाने वाले बाहरी प्रभाव को एक इडेम्पोटेंसी कुंजी या एक स्पष्ट अवशिष्ट जोखिम (residual risk) की आवश्यकता होती है।
- डाउनटाइम के दौरान छूटे हुए ऑकरेंस का क्या होता है? प्रत्येक शेड्यूल को एक
misfire_policy, अधिकतम देरी (maximum lateness), और कैच-अप कैप की आवश्यकता होती है। अन्यथा रिकवरी अचानक लाखों अप्रचलित ऑकरेंस बना सकती है। - क्या एक शेड्यूल खुद को ओवरलैप कर सकता है? डिफ़ॉल्ट
ALLOWहै, जिसमेंSKIP_IF_RUNNINGएक अन्य विकल्प है। जब साइड इफेक्ट्स को पूर्ववत (undo) नहीं किया जा सकता है, तो मनमाने इन-फ़्लाइट कार्य को बदलना असुरक्षित है। - अपडेट और कैंसलेशन की गारंटी कितनी मज़बूत है? पुराने संस्करणों के पेंडिंग ऑकरेंस अमान्य हो जाने चाहिए। किसी शेड्यूल को हटाने से वह कार्य वापस नहीं लाया जा सकता जिसे किसी वर्कर ने पहले ही क्लेम कर लिया है या पूरा कर लिया है, इसलिए API को वास्तविक स्थिति की रिपोर्ट करनी चाहिए।
- टारगेट क्या है? यह डिज़ाइन रजिस्टर्ड हैंडलर्स के लिए ड्यूरेबल कतारों पर ऑकरेंस रखता है। मनमाना उपयोगकर्ता कोड शामिल नहीं है ताकि सैंडबॉक्सिंग और कंप्यूट प्लेसमेंट शेड्यूलिंग समस्या को अस्पष्ट न करें।
- किस टेनेंट आइसोलेशन की आवश्यकता है? शेड्यूल काउंट, ट्रिगर रेट, रनिंग कॉनक्रेसी और कैच-अप रेट के लिए अलग-अलग कोटा लागू करें। घंटे की शुरुआत का एक बैच हर शार्ड और कतार का उपभोग नहीं कर सकता है।
30-सेकंड का उत्तर
“मैं शेड्यूल्स, ऑकरेंस और प्रयासों को अलग करूँगा। एक शेड्यूल एक्सप्रेशन, IANA टाइम ज़ोन, वर्शन और अगला ट्रिगर स्टोर करता है। शेड्यूलर नोड्स टाइम बकेट और शेड्यूल-ID हैश द्वारा शार्ड होते हैं और केवल एक सीमित क्षितिज (bounded horizon) को मटेरियलाइज़ करते हैं। ऑकरेंस ID शेड्यूल ID, वर्शन और मूल शेड्यूल्ड समय से प्राप्त होती है; एक यूनीक कंस्ट्रेंट फ़ेलओवर के दौरान डुप्लिकेट मटेरियलाइजेशन को रोकता है। ऑकरेंस, अगला ट्रिगर और आउटबॉक्स एक ट्रांज़ैक्शन में कमिट होते हैं, फिर एक रिले कम से कम एक बार (at least once) एक ड्यूरेबल कतार में लिखता है। वर्कर रिन्यूएबल विज़िबिलिटी लीज़ के तहत प्रोसेस करते हैं, जबकि बिज़नेस हैंडलर ऑकरेंस ID द्वारा डिडुप्लिकेट करते हैं। सख्त जॉब्स को पीक रेट के लिए प्रोविज़न किया जाता है, और फ्लेक्सिबल जॉब्स नियतात्मक जिटर (deterministic jitter) का उपयोग करते हैं। मिसफायर, ओवरलैप, टाइम-ज़ोन और कैंसलेशन व्यवहार स्पष्ट नीतियां हैं। मैं 500,000 एक साथ ट्रिगर्स, प्रत्येक हैंडऑफ़ पर क्रैश, डेलाइट-सेविंग सीमाओं और कैंसलेशन रेस के साथ मान्य करूँगा।”
चरण-दर-चरण विस्तृत विश्लेषण
घटकों को ड्रा करने से पहले डेटा प्लेन की गणना करें:
average = 200,000,000 / 86,400 ≈ 2,315 occurrences/s
strict_peak = 500,000 / 5 = 100,000 dispatches/sसख्त पीक दैनिक औसत से 43 गुना से अधिक है। यदि एक एक्टिव शेड्यूल और एक ऑकरेंस प्रत्येक लगभग 1 KB लॉजिकल स्टोरेज का उपयोग करते हैं, तो शेड्यूल मेटाडेटा लगभग 20 GB है और ऑकरेंस प्रति दिन लगभग 200 GB जोड़ते हैं। इंडेक्स, रेप्लिकस, कतार संदेश और इतिहास प्रतिधारण (retention) और अधिक जोड़ते हैं। ये विभाजन और स्टोरेज टियर्स के लिए साइज़िंग धारणाएं हैं; वास्तविक फ़ील्ड्स और इंडेक्स का लोड-टेस्ट किया जाना चाहिए।
कंट्रोल प्लेन एक्सप्रेशन्स को मान्य करता है, टेनेंट्स को अधिकृत करता है, कोटा लागू करता है, इडेम्पोटेंट रूप से बनाता है, और अपडेट्स को वर्शन करता है। एक सरलीकृत मॉडल है:
Schedule(schedule_id, tenant_id, expression, time_zone, version,
next_run_at, state, misfire_policy, max_lateness,
overlap_policy, flexible_window)
Occurrence(occurrence_id, schedule_id, schedule_version,
scheduled_for, available_at, state, attempt_count)
Attempt(attempt_id, occurrence_id, lease_token, started_at,
finished_at, result)
UNIQUE(schedule_id, schedule_version, scheduled_for)क्रिएट API कॉलर इडेम्पोटेंसी कुंजी स्वीकार करता है। यह क्रॉन एक्सप्रेशन और टाइम ज़ोन को मान्य करता है और भविष्य के कई ट्रिगर्स का पूर्वावलोकन करता है ताकि सिंटैक्टिक रूप से मान्य लेकिन अनपेक्षित एक्सप्रेशन को जल्दी पकड़ा जा सके। मूल एक्सप्रेशन और IANA ज़ोन को बनाए रखते हुए next_run_at को UTC में स्टोर करें। एक दैनिक स्थानीय-समय जॉब को पिछले UTC टाइमस्टैम्प में 24 घंटे जोड़ने के बजाय ज़ोन नियमों से अपना अगला समय प्राप्त करना चाहिए।
टाइम-ज़ोन किनारों (edges) के लिए एक स्थिर अनुबंध की आवश्यकता होती है। यह डिज़ाइन स्प्रिंग-फ़ॉरवर्ड के दौरान एक गैर-मौजूद स्थानीय समय को छोड़ देता है और जब फ़ॉल-बैक एक वॉल-क्लॉक समय को दोहराता है तो एक बार चलता है। टाइम-ज़ोन अपडेट केवल एक नए शेड्यूल संस्करण के तहत भविष्य के ऑकरेंस को प्रभावित करता है। AWS Scheduler समान स्किप-एंड-रन-वन्स व्यवहार का दस्तावेजीकरण करता है, लेकिन यह एक सार्वभौमिक शेड्यूलर नियम के बजाय यहाँ एक उत्पाद विकल्प बना हुआ है। एक भविष्य का फ़िक्स्ड-रेट प्रकार व्यतीत अवधि (elapsed duration) का उपयोग करेगा और डेलाइट सेविंग के साथ स्थानांतरित नहीं होगा।
शेड्यूल स्टोर में shard = hash(schedule_id) mod N के साथ (time_bucket, shard, next_run_at) के बराबर एक इंडेक्स होता है। शेड्यूलर नोड्स कई लॉजिकल शार्ड्स को लीज़ पर लेते हैं और एक सीमित योजना क्षितिज (bounded planning horizon) को स्कैन करते हैं, जैसे कि अगले कुछ मिनट। एक एकल ग्लोबल लीडर क्षमता और रिकवरी को सीमित करता है। शार्ड लीज़ डुप्लिकेट स्कैन को कम करते हैं, जबकि डेटाबेस विशिष्टता (uniqueness) और सशर्त लेखन (conditional writes) अंतिम शुद्धता सीमा प्रदान करते हैं।
प्रत्येक देय (due) शेड्यूल के लिए, एक ट्रांज़ैक्शन एक नियतात्मक Occurrence सम्मिलित करता है, वर्तमान शेड्यूल संस्करण से next_run_at को सशर्त रूप से आगे बढ़ाता है, और available_at के साथ एक डिस्पैच आउटबॉक्स पंक्ति लिखता है। यदि लीज़ संक्रमण के दौरान दो नोड्स ओवरलैप होते हैं, तो विशिष्टता एक (schedule_id, version, scheduled_for) ऑकरेंस छोड़ती है। सशर्त अपडेट एक पुराने नोड को अगले ट्रिगर को पीछे ले जाने से रोकता है।
पहले से एक अनंत क्रॉन इतिहास उत्पन्न न करें। एक योजना क्षितिज जो बहुत छोटा है, स्टोरेज जिटर को सीधे 5-सेकंड के SLO में पास करता है। जो बहुत लंबा है वह अपडेट और कैंसलेशन को पुराने संस्करण के ऑकरेंस के एक बड़े सेट को अमान्य करने के लिए मजबूर करता है। एक ऐसा क्षितिज चुनें जो शेड्यूलर फ़ेलओवर और एनक्यू बजट को कवर करता हो, फिर मापे गए अंतराल (lag) से इसे ट्यून करें। एक वन-टाइम शेड्यूल टर्मिनल बन जाता है; एक आवर्ती (recurring) शेड्यूल केवल एक नेक्स्ट-ट्रिगर कर्सर रखता है जबकि पुराने ऑकरेंस टियर वाले इतिहास में चले जाते हैं।
available_at के पास, एक डिस्पैच रिले आउटबॉक्स इवेंट्स को टेनेंट और प्राथमिकता द्वारा विभाजित ड्यूरेबल कतारों में लिखता है। यदि रिले कतार द्वारा संदेश स्वीकार करने के बाद लेकिन डेटाबेस पावती से पहले क्रैश हो जाता है, तो यह वही occurrence_id फिर से भेजता है। वह डुप्लिकेट जानबूझकर है। एनक्यू करने से पहले भेजा गया चिह्नित करना कार्य को छोड़ सकता है, जबकि चिह्नित करने से पहले एनक्यू करना इसे डुप्लिकेट कर सकता है। एक ट्रांज़ैक्शनल आउटबॉक्स ट्रेड-ऑफ़ को एक स्पष्ट, इडेम्पोटेंट रूप से पुनः प्रयास करने योग्य एट-लीस्ट-वन्स पथ बनाता है।
पांच लाख टॉप-ऑफ-ऑवर जॉब्स के लिए अतिरिक्त पोलिंग थ्रेड्स से अधिक की आवश्यकता होती है। प्रत्येक टाइम बकेट को पर्याप्त शेड्यूल-ID हैश शार्ड्स में विभाजित करें। यदि लोड परीक्षण दिखाते हैं कि एक शार्ड वास्तविक ट्रांज़ैक्शन, इंडेक्स और कतार राइट्स के साथ सुरक्षित रूप से प्रति सेकंड Q डिस्पैच करता है, तो सख्त प्लेन को कम से कम ceil(100,000 / Q) एक साथ उपलब्ध शार्ड्स और विफलता हेडरूम की आवश्यकता होती है। कतार टेनेंट-भारित निष्पक्षता (tenant-weighted fairness) और दर कोटा लागू करती है ताकि एक टेनेंट सख्त लेन का उपभोग न कर सके।
5-मिनट की विंडो वाले जॉब्स नियतात्मक जिटर का उपयोग करते हैं: available_at = scheduled_for + hash(occurrence_id) mod 300s। समान ऑकरेंस को पुनः प्रयासों और फ़ेलओवर के बाद समान समय मिलता है, जिससे संबंधित ट्रिगर्स को फैलाते हुए व्यवहार प्रतिलिपि प्रस्तुत करने योग्य (reproducible) हो जाता है। सख्त जॉब्स मूल समय और आरक्षित क्षमता बनाए रखते हैं। Amazon की Builders' Library इसी तरह आवधिक हाउसकीपिंग जॉब्स पर जिटर को सहसंबंधित विफलता (correlated failure) को कम करने के तरीके के रूप में पहचानती है।
एक वर्कर समयबद्ध विज़िबिलिटी लीज़ के तहत एक ऑकरेंस प्राप्त करता है और लंबे काम के लिए हार्टबीट्स के साथ इसे रिन्यू करता है। लीज़ की समाप्ति संदेश को फिर से दृश्यमान बनाती है, और विंडो के दौरान भी डुप्लिकेट डिलीवरी को बाहर नहीं किया जा सकता है। इसलिए स्टेट मशीन लीज़ को एग्ज़ैक्टली-वन्स के रूप में नहीं मान सकती है:
SCHEDULED -> ENQUEUED -> RUNNING -> SUCCEEDED
| |
| +-> RETRY_WAIT -> ENQUEUED
+------> DEAD
Side states: MISSED, CANCELED, SKIPPED_OVERLAPप्रत्येक क्लेम को एक नया lease_token या बढ़ती हुई प्रयास पीढ़ी (attempt generation) मिलती है। पूर्णता अपडेट वर्तमान टोकन से मेल खाना चाहिए ताकि एक टाइम-आउट वर्कर एक नए प्रयास की स्थिति को अधिलेखित (overwrite) न कर सके। यह फेंसिंग शेड्यूलर स्थिति की रक्षा करती है, पुराने वर्कर द्वारा पहले से किए गए बाहरी प्रभाव की नहीं। व्यावसायिक इडेम्पोटेंसी प्रभाव के समान ट्रांज़ैक्शन में occurrence_id को एक यूनीक कुंजी के रूप में, या डाउनस्ट्रीम API की इडेम्पोटेंसी कुंजी के रूप में उपयोग करती है। यदि किसी बाहरी लक्ष्य में इडेम्पोटेंसी का अभाव है और उससे पूछताछ नहीं की जा सकती है, तो डुप्लिकेट जोखिम बना रहता है।
त्रुटि वर्ग के अनुसार पुनः प्रयास करें। स्थायी पैरामीटर त्रुटियाँ DEAD पर जाती हैं। नेटवर्क विफलताएं, थ्रॉटलिंग और अस्थायी 5xx प्रतिक्रियाएं अधिकतम प्रयासों, ऑकरेंस समय सीमा और टेनेंट बजट द्वारा सीमित, पूर्ण जिटर के साथ एक्सपोनेंशियल बैकऑफ़ का उपयोग करती हैं। एक कतार DLQ समाप्त हो चुके ऑकरेंस को बनाए रखती है। मैनुअल रीप्ले समान occurrence_id रखता है; एक नया ID निर्दिष्ट करना डिडुप्लिकेशन को बायपास कर देगा।
कंट्रोल-प्लेन रिकवरी के लिए स्पष्ट मिसफायर नीतियों की आवश्यकता होती है। SKIP अधिकतम देरी से आगे के ऑकरेंस को MISSED के रूप में चिह्नित करता है। FIRE_ONCE केवल नवीनतम छूटे हुए ऑकरेंस का उत्सर्जन करता है। CATCH_UP एक टेनेंट कैच-अप दर के अधीन, अधिकतम K उत्सर्जित करता है। Kubernetes की प्रारंभिक समय सीमा (starting deadline) और छूटे हुए शेड्यूल की सीमाएं समान निर्णय को उजागर करती हैं: अनबाउंडेड रिकवरी या तो आवश्यक काम खो देती है या एक रिकवरी स्टॉर्म बनाती है।
SKIP_IF_RUNNING नए ऑकरेंस को SKIPPED_OVERLAP चिह्नित करने से पहले उसी शेड्यूल के वर्तमान RUNNING ऑकरेंस की परमाणु रूप से (atomically) जाँच करता है। परमाणु स्थिति संक्रमण के बिना, दो ऑकरेंस दोनों किसी पूर्ववर्ती का निरीक्षण नहीं कर सकते हैं। रद्द करना या अपडेट करना शेड्यूल संस्करण को बढ़ाता है और अनक्लेम किए गए पुराने-संस्करण ऑकरेंस को अमान्य करता है। वर्कर साइड इफेक्ट से पहले संस्करण और कैंसलेशन मार्कर की फिर से जांच करते हैं। शुरू किए गए कार्य के लिए सहकारी कैंसलेशन (cooperative cancellation) की आवश्यकता होती है, और पूर्ण किए गए बाहरी प्रभावों को शेड्यूलर द्वारा रोल बैक नहीं किया जा सकता है।
अवलोकन क्षमता (Observability) गारंटी का पालन करती है: schedule_lag = enqueued_at - scheduled_for के लिए p50/p95/p99; प्रति टाइम बकेट पेंडिंग पंक्तियाँ; मटेरियलाइजेशन अंतराल (lag); विशिष्टता संघर्ष (uniqueness conflicts); आउटबॉक्स बैकलॉग; कतार आयु; डुप्लिकेट क्लेम; रिट्राइज़ और DLQ; MISSED और ओवरलैप स्किप; टेनेंट थ्रॉटलिंग; घड़ी ऑफ़सेट; और प्रत्येक ऑकरेंस स्थिति में बिताया गया समय। API उपलब्धता यह साबित नहीं करती है कि अपेक्षित ऑकरेंस समय पर कतारों में पहुँचे हैं।
स्वीकृति परीक्षण सबसे पहले घंटे की शुरुआत में 500,000 सख्त ऑकरेंस को इंजेक्ट करता है और 5-सेकंड p99 प्लस टेनेंट निष्पक्षता की जांच करता है। फिर इंसर्शन से पहले, ट्रांज़ैक्शन कमिट के बाद, और कतार भेजने के बाद शेड्यूलर को क्रैश करें; पुष्टि करें कि कोई मौन चूक (silent omission) नहीं है और उसी ऑकरेंस ID द्वारा डिडुप्लिकेशन है। इसके अलावा एक वर्कर द्वारा अपने प्रभाव के बाद पावती खोने, लीज़ समाप्ति, दस मिनट के कंट्रोल-प्लेन आउटेज के बाद सभी तीन मिसफायर नीतियों, दोनों डेलाइट-सेविंग संक्रमणों, अपडेट और कैंसलेशन रेस, लंबे समय तक चलने वाले ओवरलैप और एक टेनेंट के कैच-अप स्टॉर्म को कवर करें।
मज़बूत नमूना उत्तर
“मैं SLO को शेड्यूल्ड समय से ड्यूरेबल कतार स्वीकृति के रूप में परिभाषित करूँगा, जिसमें निष्पादन शामिल नहीं है। दो सौ मिलियन दैनिक ट्रिगर्स का औसत लगभग 2,315 प्रति सेकंड है, लेकिन पांच सेकंड के भीतर 500,000 टॉप-ऑफ-ऑवर ट्रिगर्स के लिए प्रति सेकंड 100,000 के लिए साइज़ किए गए एक सख्त प्लेन की आवश्यकता होती है। फ्लेक्सिबल काम को पांच मिनट में नियतात्मक रूप से फैलाया जा सकता है।
मॉडल शेड्यूल्स, ऑकरेंस और प्रयासों को अलग करता है। एक शेड्यूल अपने क्रॉन एक्सप्रेशन, IANA ज़ोन, संस्करण और next_run_at को स्टोर करता है। एक ऑकरेंस ID शेड्यूल ID, संस्करण और scheduled_for से प्राप्त होती है और इसमें एक यूनीक कंस्ट्रेंट होता है। शेड्यूलर नोड्स टाइम बकेट और शेड्यूल-ID हैश द्वारा शार्ड होते हैं और स्कैनिंग के लिए शार्ड्स को लीज़ पर लेते हैं। एक ट्रांज़ैक्शन ऑकरेंस सम्मिलित करता है, अगले ट्रिगर को आगे बढ़ाता है, और एक डिस्पैच आउटबॉक्स लिखता है, इसलिए फ़ेलओवर चुपचाप काम को नहीं छोड़ता है और एक दोहराया गया रिले केवल वही ऑकरेंस ID भेजता है।
कतार और वर्कर एट-लीस्ट-वन्स सेमेंटिक्स का उपयोग करते हैं। वर्करों के पास रिन्यूएबल विज़िबिलिटी लीज़ होती है, और पूर्णता वर्तमान लीज़ टोकन से मेल खानी चाहिए। बिज़नेस हैंडलर ऑकरेंस ID का उपयोग डेटाबेस यूनीक कुंजी या डाउनस्ट्रीम इडेम्पोटेंसी कुंजी के रूप में करता है। लीज़ की समाप्ति तब व्यावसायिक प्रभावों को जोड़े बिना प्रयासों को जोड़ सकती है; इडेम्पोटेंसी के बिना एक बाहरी लक्ष्य एक स्पष्ट डुप्लिकेट जोखिम बनाए रखता है।
मिसफायर, ओवरलैप, टाइम-ज़ोन और कैंसलेशन व्यवहार API नीतियां हैं। डाउनटाइम के बाद, एक शेड्यूल स्किप कर सकता है, एक बार ट्रिगर हो सकता है, या अधिकतम K बार कैच अप कर सकता है। एक गैर-मौजूद क्रॉन समय को छोड़ दिया जाता है और एक दोहराया गया वॉल-क्लॉक समय एक बार चलता है। अपडेट संस्करण को बढ़ाते हैं, और वर्कर साइड इफेक्ट्स से पहले फिर से जांच करते हैं। मैं टॉप-ऑफ-ऑवर पीक, प्रत्येक क्रैश विंडो, डुप्लिकेट संदेशों, डेलाइट-सेविंग सीमाओं और कैंसलेशन रेस का परीक्षण करूँगा, जबकि शेड्यूल लैग, ड्यू बैकलॉग, डुप्लिकेट क्लेम, छूटे हुए ऑकरेंस, DLQ और टेनेंट थ्रॉटलिंग की निगरानी करूँगा।”
सामान्य गलतियाँ
- शेड्यूल, ऑकरेंस और प्रयास को एक पंक्ति में संयोजित करना → रिट्राइज़ इतिहास को अधिलेखित कर देते हैं और अपडेट पुराने ऑकरेंस की पहचान नहीं कर सकते हैं →
Schedule,Occurrence, औरAttemptको अलग करें। - 2,315-प्रति-सेकंड दैनिक औसत के लिए साइज़िंग → पांच लाख टॉप-ऑफ-ऑवर ट्रिगर्स गंभीर अंतराल (lag) का कारण बनते हैं → सख्त पीक पर शार्ड्स का लोड-परीक्षण करें और फ्लेक्सिबल काम को नियतात्मक रूप से फैलाएं।
- इन-मेमोरी मिन-हीप के साथ एक ग्लोबल लीडर का उपयोग करना → लीडर एक क्षमता और रिकवरी बाधा बन जाता है, और पुनरारंभ सभी भविष्य के काम का पुनर्निर्माण करता है → एक ड्यूरेबल टाइम इंडेक्स, लॉजिकल शार्ड्स और एक सीमित क्षितिज का उपयोग करें।
- कतार लिखने से पहले भेजा गया चिह्नित करना → एक कतार विफलता चुपचाप एक ऑकरेंस को छोड़ देती है → एक आउटबॉक्स को ट्रांज़ैक्शनल रूप से लिखें और कम से कम एक बार रिले करें।
- दावा करना कि लॉक और विज़िबिलिटी टाइमआउट एग्ज़ैक्टली-वन्स की गारंटी देते हैं → टाइमआउट और खोई हुई पावती अभी भी प्रयासों को ओवरलैप करती है → स्थिर ऑकरेंस ID, फेंसिंग टोकन और व्यावसायिक इडेम्पोटेंसी को मिलाएं।
- रिकवरी के बाद हर छूटे हुए ऐतिहासिक ऑकरेंस को रीप्ले करना → लाखों अप्रचलित कार्य एक दूसरा आउटेज बनाते हैं → अधिकतम देरी, कैच-अप कैप और टेनेंट दरें निर्धारित करें।
- स्थानीय दैनिक क्रॉन के लिए UTC में 24 घंटे जोड़ना → डेलाइट सेविंग में वॉल-क्लॉक समय ड्रिफ्ट होता है → IANA ज़ोन बनाए रखें और अगले स्थानीय ऑकरेंस की गणना करें।
- पॉज़ या कैंसिल करने के लिए एक पंक्ति को हटाना → मटेरियलाइज़्ड या कतारबद्ध कार्य अभी भी चल सकता है, और ऑडिट इतिहास गायब हो जाता है → संस्करण द्वारा अमान्य करें और साइड इफेक्ट्स से पहले स्थिति की फिर से जांच करें।
- प्रत्येक टेनेंट को एक FIFO कतार पर रखना → एक बड़ा टॉप-ऑफ-ऑवर बैच अन्य टेनेंट्स को ब्लॉक करता है → टेनेंट-जागरूक निष्पक्ष शेड्यूलिंग का उपयोग करें और ट्रिगर और कॉनक्रेसी कोटा अलग करें।
- केवल API सफलता की निगरानी करना → एक शेड्यूल सफलतापूर्वक बनाया जा सकता है और कभी भी समय पर ट्रिगर नहीं हो सकता है → शेड्यूल लैग, ड्यू बैकलॉग, छूटे हुए ऑकरेंस और स्टेट समाधान (reconciliation) को ट्रैक करें।
फ़ॉलो-अप
फ़ॉलो-अप 1: क्या होगा यदि कोई शेड्यूलर कतार भेजने के बाद लेकिन आउटबॉक्स को अपडेट करने से पहले क्रैश हो जाता है?
रिले वही occurrence_id फिर से भेजता है। कतार उपभोक्ता और बिज़नेस टारगेट उस ID पर डिडुप्लिकेट करते हैं, और आउटबॉक्स पावती सशर्त है। चूक पर दोहराव को चुना जाता है क्योंकि डेटाबेस और कतार एक ट्रांज़ैक्शन साझा नहीं करते हैं। एक ट्रांज़ैक्शनल लॉग विंडो को संकीर्ण कर सकता है, लेकिन बाहरी प्रभावों के लिए अभी भी इडेम्पोटेंसी की आवश्यकता होती है।
फ़ॉलो-अप 2: आप एक्टिव-एक्टिव क्षेत्रों का समर्थन कैसे करेंगे?
प्रत्येक शेड्यूल को एक होम क्षेत्र और एक बढ़ती पीढ़ी (generation) निर्दिष्ट करें। केवल वर्तमान पीढ़ी रखने वाला क्षेत्र ही ऑकरेंस को मटेरियलाइज़ कर सकता है, जबकि निष्पादन कतारें टारगेट क्षेत्रों में रूट हो सकती हैं। नया क्षेत्र ड्यूरेबल कर्सर से फिर से शुरू होने से पहले फ़ेलओवर पीढ़ी को आगे बढ़ाता है। एक विश्व स्तर पर अद्वितीय ऑकरेंस कुंजी या एकत्रीकरण परत अंतिम डुप्लिकेट सीमा बनी हुई है। क्षेत्रीय फ़ेलओवर वाला एक सिंगल-राइटर कंट्रोल प्लेन तब सरल होता है जब क्रॉस-रीजन राइट्स अनावश्यक होते हैं।
फ़ॉलो-अप 3: फ़ॉल-बैक पर, स्थानीय 01:30 दो बार होता है। कितने रन होने चाहिए?
इसका कोई सार्वभौमिक उत्तर नहीं है; यह शेड्यूल अनुबंध का हिस्सा है। यह डिज़ाइन स्थानीय तिथि, वॉल-क्लॉक समय और ज़ोन के साथ दो UTC उम्मीदवारों को संक्षिप्त करके एक बार चलता है। एक वित्तीय समाधान जिसके लिए दोनों भौतिक क्षणों की आवश्यकता होती है, विभिन्न scheduled_for मानों के साथ दो ऑकरेंस चुनेगा। API को सहेजने से पहले भविष्य के रनों का पूर्वावलोकन करना चाहिए।
फ़ॉलो-अप 4: एक जॉब दो घंटे तक चलता है लेकिन प्रति घंटा दोहराता है। क्या होता है?
ALLOW उन्हें समवर्ती रूप से चलाता है। SKIP_IF_RUNNING परमाणु रूप से नए ऑकरेंस को SKIPPED_OVERLAP के रूप में चिह्नित करता है। यदि उत्पाद को प्रतीक्षा की आवश्यकता है, तो QUEUE_ONE जोड़ें और अधिकतम एक पेंडिंग ऑकरेंस बनाए रखें। पुराने रन को बदलना केवल तभी सुरक्षित होता है जब हैंडलर सहकारी कैंसलेशन का समर्थन करते हैं क्योंकि प्रभाव पहले से मौजूद हो सकते हैं।
फ़ॉलो-अप 5: शेड्यूलर एक दिन के लिए डाउन है। आप लक्ष्यों को अभिभूत किए बिना कैसे रिकवर करते हैं?
प्रति शेड्यूल SKIP, FIRE_ONCE, या बाउंडेड CATCH_UP लागू करें, फिर टेनेंट और टारगेट क्षमता द्वारा थ्रॉटल करें। कर्सर को वर्तमान समय से बदलने के बजाय ड्यूरेबल next_run_at से स्कैनिंग फिर से शुरू करें। सबसे पुराने पेंडिंग समय और अनुमानित ड्रेन अवधि को ट्रैक करें, और सख्त नए काम को कैच-अप क्षमता से अलग करें।
फ़ॉलो-अप 6: आप कैसे साबित करते हैं कि कोई मौन चूक नहीं हुई थी?
एक ऑफ़लाइन समाधानकर्ता (offline reconciler) स्वतंत्र रूप से शेड्यूल संस्करणों और समय नियमों से अपेक्षित ऑकरेंस सेट की पुनर्गणना करता है, फिर इसकी तुलना Occurrence यूनीक-की सेट से करता है। प्रत्येक अपेक्षित आइटम को सफल, विफल, रद्द, छूटा हुआ या अनुपस्थित होना चाहिए। ऑनलाइन मेट्रिक्स अंतराल (lag) का पता लगाते हैं; समाधान (reconciliation) उन अंतरालों का पता लगाता है जहां सिस्टम ने कोई त्रुटि रिपोर्ट नहीं की क्योंकि कोई ऑकरेंस कभी बनाया ही नहीं गया था।