प्रॉम्प्ट और संदर्भ
अधिकतम 20 स्टेप्स की ग्राहक-परिभाषित (customer-defined) प्रक्रियाओं के लिए एक वर्कफ़्लो इंजन डिज़ाइन करें। एक स्टेप के लिए मानवीय स्वीकृति की आवश्यकता होती है और इसमें दिनों तक प्रतीक्षा करनी पड़ सकती है; गतिविधियां (activities) विफल हो सकती हैं, दो बार डिलीवर हो सकती हैं, या रिस्पॉन्स खो जाने पर भी सफल हो सकती हैं। सिस्टम को विफलताओं से रिकवर होना चाहिए और टाइमआउट, कैंसलेशन, ऑडिट और वर्ज़न अपग्रेड का समर्थन करना चाहिए। स्टेट मॉडल, शेड्यूलिंग, आइडमपोटेंसी, कॉलबैक सुरक्षा, स्केल और ट्रेड-ऑफ़ समझाएं।
यह सिस्टम-डिज़ाइन प्रश्न बैकएंड, प्लेटफ़ॉर्म और इंफ्रास्ट्रक्चर भूमिकाओं के लिए उपयुक्त है। इसका मुख्य ध्यान ड्यूरेबल निष्पादन सिमेंटिक्स (durable execution semantics) पर है, न कि किसी साधारण कतार (queue) का चित्र बनाने पर। 20-स्टेप की सीमा और कई दिनों की प्रतीक्षा इंटरव्यू की धारणाएं (assumptions) हैं; पहले थ्रूपुट, लेटेंसी, टेनेंट आइसोलेशन, डेटा संवेदनशीलता, रिकवरी लक्ष्य और डेटा प्रतिधारण (retention) दायित्वों को स्पष्ट करें।
इंटरव्यूअर क्या जांच रहा है
इंटरव्यूअर वर्कफ़्लो स्टेट, गतिविधि निष्पादन और बाहरी साइड इफेक्ट्स के बीच स्पष्ट अलगाव की तलाश कर रहा है; यह स्पष्ट स्वीकृति कि गतिविधियां कम से कम एक बार (at least once) चल सकती हैं; और व्यावसायिक नियमों (business invariants) से जुड़ी आइडमपोटेंसी कुंजियाँ। मानवीय स्वीकृति के लिए एक जाली न बनाए जा सकने वाले (unforgeable), समाप्त होने वाले (expiring) और एकल-उपयोग (single-use) क्रेडेंशियल की आवश्यकता होती है। उत्तर में इवेंट हिस्ट्री, स्नैपशॉट, टाइमर, कैंसलेशन, वर्ज़न और ऑपरेशनल रिपेयर को भी परिभाषित किया जाना चाहिए।
पहले स्पष्ट करने योग्य प्रश्न
- प्रति-टेनेंट कॉन्करेंसी, वर्कफ़्लो-स्टार्ट दर और अधिकतम प्रतीक्षा समय क्या हैं?
- क्या गतिविधियां फंक्शन्स, कंटेनर्स या बाहरी HTTP सेवाएं हैं, और कौन से साइड इफेक्ट्स अपरिवर्तनीय हैं?
- स्वीकृतकर्ताओं (approvers) को कैसे प्रमाणित, अधिकृत और बदला जाता है? क्या कोरम स्वीकृति की आवश्यकता है?
- क्या पुनः प्रयास (retries) किसी गतिविधि को दोहरा सकते हैं, और क्या व्यावसायिक सेवा एक आइडमपोटेंसी कुंजी स्वीकार कर सकती है?
- परिभाषाओं को कैसे प्रकाशित, फ़्रीज़ और माइग्रेट किया जाता है? क्या चल रहे इंस्टेंसेस नए वर्ज़न का पालन करते हैं?
- किन ऑडिट फ़ील्ड्स को बनाए रखा जाना चाहिए, और कौन उन्हें पढ़ या बदल सकता है?
- क्या कैंसलेशन, पॉज़, मैन्युअल पुनः प्रयास या स्टेप स्किप सामान्य उत्पाद संचालन हैं?
30-सेकंड का उत्तर ढांचा (Framework)
“मैं एक वर्कफ़्लो को एक ड्यूरेबल स्टेट मशीन के रूप में मॉडल करूँगा: परिभाषा वर्ज़न्स, रन, गतिविधि के प्रयास, एक इवेंट लॉग और एक वर्तमान स्नैपशॉट को अलग-अलग स्टोर करें। शेड्यूलर पुनः प्रयास योग्य गतिविधि कार्यों को डिलीवर करता है; वर्कर्स गतिविधि आईडी, प्रयास और आइडमपोटेंसी कुंजी के साथ परिणामों की रिपोर्ट करते हैं, और स्टेट मशीन उनका डुप्लिकेट हटाती है। एक मानवीय स्वीकृति को रन, स्टेप, टेनेंट और स्वीकृति वर्ज़न से जुड़ा एक अल्पकालिक एकल-उपयोग टोकन मिलता है। टाइमर, टाइमआउट और कैंसलेशन ड्यूरेबल इवेंट्स हैं। मैं पार्टीशन की गई कतारों और टेनेंट कोटा के साथ स्केल करूँगा, फिर रीप्ले, ऑडिट और फॉल्ट इंजेक्शन के साथ रिकवरी को मान्य करूँगा।”
चरण-दर-चरण उत्तर
पहले निष्पादन मॉडल को परिभाषित करें। एक वर्कफ़्लो परिभाषा एक अपरिवर्तनीय (immutable) वर्ज़न है जिसमें स्टेप के प्रकार, इनपुट मैपिंग, टाइमआउट, पुनः प्रयास नीतियां और क्षतिपूर्ति (compensation) नियम शामिल होते हैं। एक रन एक फ़्रीज़ किए गए वर्ज़न को संदर्भित करता है, ताकि एक नई परिभाषा प्रकाशित करने से इतिहास अपने आप न बदले। अपेंड-ओनली (append-only) इवेंट लॉग से स्टेट का पुनर्निर्माण करें; रीड्स को तेज़ करने के लिए स्नैपशॉट का उपयोग करें। इवेंट जोड़ने के लिए एक सीक्वेंस या वर्ज़न स्थिति की आवश्यकता होती है ताकि समवर्ती लेखक (concurrent writers) एक दूसरे को अधिलेखित (overwrite) न कर सकें।
डेटाबेस ट्रांज़ैक्शन के भीतर किसी बाहरी सेवा को कॉल न करें। एक ActivityScheduled इवेंट कमिट करें, शेड्यूलर को टास्क को कतारबद्ध करने दें, एक वर्कर को लीज (lease) प्राप्त करने और सेवा को कॉल करने दें, फिर ActivitySucceeded, ActivityFailed, या ActivityTimedOut कमिट करें। केवल अपेक्षित रन, स्टेप और प्रयास के परिणामों को ही स्वीकार करें। देर से आने वाले या डुप्लिकेट परिणाम ऑडिट साक्ष्य हैं, स्टेट ट्रांज़िशन नहीं।
एक न्यूनतम स्टेट मॉडल इस प्रकार है:
| Entity | Key fields | Purpose |
|---|---|---|
| DefinitionVersion | tenant, definition, version, digest | Freeze steps and policies |
| WorkflowRun | run, definitionVersion, status, sequence | Track an instance |
| Event | run, sequence, type, payload, createdAt | Facts and replay |
| ActivityAttempt | step, attempt, lease, idempotencyKey, status | Delivery, lease, result |
| Approval | step, tokenHash, approver, expiresAt, status | Human approval credential |
| Timer | run, step, fireAt, generation, status | Wakeups, delays, timeouts |
डिलीवरी कम से कम एक बार (at least once) होती है; कतार की पावती (acknowledgement) व्यावसायिक पूर्णता नहीं है। संदेशों में रन आईडी, स्टेप आईडी, प्रयास, परिभाषा वर्ज़न और एक आइडमपोटेंसी कुंजी होती है। एक लीज दो उपभोक्ताओं को एक साथ काम करने से रोकती है, जबकि एक फेंसिंग टोकन या सशर्त राइट (conditional write) किसी पुराने वर्कर को अस्वीकार कर देता है। लीज समाप्त होने पर पुन: डिलीवरी की अनुमति मिलती है, लेकिन डुप्लिकेट बाहरी प्रभाव गतिविधि अनुबंध पर निर्भर करते हैं।
कई स्तरों पर आइडमपोटेंसी को संभालें। स्टेट-मशीन इवेंट्स एक अद्वितीय (run, sequence) कुंजी का उपयोग करते हैं। गतिविधि परिणाम (run, step, idempotencyKey) का उपयोग करते हैं। भुगतान, ईमेल, या किसी व्यावसायिक सेवा में राइट्स को उसी कुंजी को स्वीकार करना चाहिए या व्यावसायिक विशिष्टता प्रतिबंध (uniqueness constraint) लागू करना चाहिए। यदि कोई कॉल सफल होती है और रिस्पॉन्स खो जाता है, तो पुनः प्रयास को पहले से पूरा परिणाम या सुरक्षित डुप्लिकेट वापस करना चाहिए। एंड-टू-एंड सटीक रूप से एक बार (exactly once) का दावा न करें। गैर-आइडमपोटेंट प्रभावों के लिए, मानवीय समीक्षा, क्षतिपूर्ति, या बिना-पुनः प्रयास नीति का उपयोग करें।
स्वीकृति URL कोई प्राधिकरण (authorization) नहीं है। उच्च-एन्ट्रॉपी यादृच्छिक सामग्री उत्पन्न करें, केवल उसका हैश स्टोर करें, और टोकन को टेनेंट, रन, स्टेप, एक्शन और समाप्ति से बांधें। कॉलबैक पर, टोकन, हस्ताक्षर या लॉगिन पहचान, CSRF सुरक्षा, एकल-उपयोग स्थिति और वर्तमान वर्कफ़्लो स्टेप को मान्य करें। सबमिशन के समय स्वीकृतकर्ता के प्राधिकरण की पुन: जाँच करें। स्वीकृतियां और अस्वीकृतियां छेड़छाड़-रोधी ऑडिट इवेंट्स बन जाती हैं; समाप्त हो चुका कॉलबैक अमान्य होता है।
टाइमर को बनाए रखें (persist करें)। टाइमआउट या प्रतीक्षा बनाते समय fireAt और एक जनरेशन स्टोर करें। एक शेड्यूलर एक समय इंडेक्स या बकेट को स्कैन करता है, सशर्त अपडेट के साथ देय टाइमर पर दावा करता है, और जनरेशन और स्टेट शर्तों के साथ दोहराव को हटाता है। रीस्टार्ट होने पर स्टोरेज से रिकवरी होती है। स्वीकृति पूर्ण होना या कैंसलेशन पुराने टाइमर को अप्रचलित चिह्नित करता है; इन-मेमोरी स्लीप को कई दिनों तक वर्कर को रोककर नहीं रखना चाहिए।
कैंसलेशन, पॉज़ और रिपेयर स्पष्ट स्टेट-मशीन कमांड्स हैं। कैंसलेशन इरादे को रिकॉर्ड करता है और उस काम को रोकता है जो शुरू नहीं हुआ है; चल रहे किसी बाहरी प्रभाव को जादुई रूप से पूर्ववत नहीं किया जा सकता है, इसलिए इसके परिणाम की प्रतीक्षा करें या क्षतिपूर्ति चलाएं। व्यवस्थापक द्वारा स्किप, पुनः प्रयास और इनपुट संपादन के लिए प्राधिकरण, एक कारण, पुरानी स्टेट, नई स्टेट और एक ऑडिट इवेंट की आवश्यकता होती है। स्नैपशॉट को सीधे कभी भी संपादित न करें, अन्यथा रीप्ले से भिन्न परिणाम प्राप्त होगा।
प्रति रन वर्ज़न्स को अलग करें। एक नई परिभाषा को एक नया डाइजेस्ट मिलता है; मौजूदा रन डिफ़ॉल्ट रूप से पुराने वर्ज़न को बनाए रखते हैं। एक माइग्रेशन को संगत स्टेट और इनपुट्स को परिभाषित करना चाहिए, कोई भी आवश्यक स्वीकृति प्राप्त करनी चाहिए, और दोनों वर्ज़न्स के साथ एक WorkflowMigrated इवेंट जोड़ना चाहिए। वर्कर्स केवल उसी परिभाषा वर्ज़न को स्वीकार करते हैं जिसे वे निष्पादित करते हैं, जिससे कोई पुराना टास्क किसी नई स्टेट मशीन को गलत तरीके से आगे बढ़ाने से रुकता है।
टेनेंट या रन आईडी पर पार्टीशन करके स्केल करें। अत्यधिक सक्रिय टेनेंट्स (hot tenants) को कॉन्करेंसी कोटा दें और गतिविधि प्रकार और प्राथमिकता के आधार पर वर्कर पूल को अलग करें। पार्टीशन किए गए स्टोरेज में इवेंट्स जोड़ें, ऑनलाइन डेटाबेस में स्नैपशॉट और इंडेक्स रखें, संवेदनशील पेलोड को एन्क्रिप्ट करें और प्रतिधारण लागू करें। बैकप्रेशर, डेड लेटर्स, लीज मेट्रिक्स और दर सीमाएं (rate limits) जोड़ें ताकि कोई एक अनियंत्रित वर्कफ़्लो वैश्विक क्षमता का उपभोग न कर सके।
ऑब्ज़र्वेबिलिटी को रनटाइम और व्यावसायिक ऑपरेटरों दोनों की सेवा करनी चाहिए। वर्तमान स्टेप, प्रतीक्षा का कारण, प्रयास, कतार विलंब, टाइमर विलंब, स्वीकृति में बिताया गया समय, पुनः प्रयास प्रवर्धन (retry amplification), क्षतिपूर्ति परिणाम और वर्ज़न रिकॉर्ड करें। ट्रेस में रन, स्टेप और प्रयास पहचानकर्ता हो सकते हैं, जबकि संवेदनशील इनपुट नियंत्रित ऑडिट स्टोरेज में रहते हैं। संचालन दृश्य को अगली कार्रवाई की व्याख्या करनी चाहिए; "प्रतीक्षा" का अर्थ "विफल" नहीं है।
विफलताओं को इंजेक्ट करें: इवेंट कमिट के बाद क्रैश, डुप्लिकेट संदेश, लीज समाप्ति, खोए हुए रिस्पॉन्स के साथ सफल गतिविधि, रीप्ले की गई स्वीकृति, डुप्लिकेट टाइमर, डेटाबेस आउटेज, कतार बैकलॉग, बाधित वर्ज़न डिप्लॉयमेंट, और समाप्त टेनेंट कोटा। अवलोकनीय परिणामों को परिभाषित करें: पुरानी स्टेट वापस नहीं आती है, बिना अनुबंध के कोई साइड इफेक्ट दोहराया नहीं जाता है, एक टोकन का दो बार उपभोग नहीं किया जा सकता है, और रिकवरी अंततः जारी रहती है या एक स्पष्ट मानवीय स्थिति में प्रवेश करती है।
उच्च गुणवत्ता वाला नमूना उत्तर
“मैं वर्कर्स को वर्कफ़्लो स्टेट याद रखने देने के बजाय एक ड्यूरेबल स्टेट मशीन बनाऊंगा। परिभाषा वर्ज़न्स अपरिवर्तनीय हैं और प्रत्येक रन एक वर्ज़न को पिन करता है; इवेंट लॉग तथ्यों का स्रोत है और स्नैपशॉट रीड्स को तेज़ करता है। स्टेट मशीन एक शेड्यूलिंग इवेंट कमिट करती है, कतार कम से कम एक बार डिलीवर करती है, और वर्कर रन, स्टेप, प्रयास और एक आइडमपोटेंसी कुंजी के साथ रिपोर्ट करता है। डुप्लिकेट या पुराने परिणाम ऑडिट प्रविष्टियां हैं, अमान्य ट्रांज़िशन नहीं।
एक स्वीकृति टेनेंट, रन, स्टेप और एक्शन से बंधा हुआ एकल-उपयोग टोकन बनाती है; केवल उसका हैश संग्रहीत किया जाता है और यह समाप्त हो जाता है। कॉलबैक पहचान, अनुमतियों, CSRF, टोकन स्थिति और वर्तमान स्टेप की जांच करता है, फिर सशर्त रूप से टोकन का उपभोग करता है और एक ऑडिट इवेंट जोड़ता है। स्वीकृति, अस्वीकृति, टाइमआउट और कैंसलेशन इवेंट्स हैं, प्रत्यक्ष स्नैपशॉट संपादन नहीं।
टाइमर fireAt और जनरेशन को बनाए रखते हैं। एक बकेटेड शेड्यूलर सशर्त राइट्स के साथ उन पर दावा करता है; रीस्टार्ट उन्हें रिकवर करता है और डुप्लिकेट फ़ायरिंग को हटा दिया जाता है। लीज समवर्ती वर्कर्स को रोकती है और फेंसिंग टोकन पुराने राइट्स को अस्वीकार करते हैं। सिद्ध डाउनस्ट्रीम आइडमपोटेंसी अनुबंध के बिना भुगतान या ईमेल सटीक रूप से एक बार नहीं हो सकते; डाउनस्ट्रीम कुंजियों, विशिष्टता, क्षतिपूर्ति या मानवीय प्रबंधन का उपयोग करें।
रन चुपचाप नई परिभाषाओं का पालन नहीं करते हैं; माइग्रेशन दोनों वर्ज़न्स के साथ एक इवेंट जोड़ता है। टेनेंट और रन द्वारा पार्टीशन करें, hot-tenant कोटा को अलग करें, और गतिविधि प्रकार द्वारा वर्कर पूल का उपयोग करें। अपेंड-ओनली इवेंट्स, ऑनलाइन स्नैपशॉट, एन्क्रिप्टेड ऑडिट डेटा और प्रतिधारण को स्तरित करें। फॉल्ट इंजेक्शन में क्रैश, पुन: डिलीवरी, खोए हुए रिस्पॉन्स, कॉलबैक रीप्ले, डुप्लिकेट टाइमर और बाधित वर्ज़न डिप्लॉयमेंट शामिल होने चाहिए।”
सामान्य गलतियाँ
- कतार पावती (ack) को पूर्णता मानना → प्रभाव के बाद एक वर्कर क्रैश हो सकता है और संदेश को फिर से प्राप्त कर सकता है → ड्यूरेबल स्टेट और आइडमपोटेंट परिणामों के साथ डुप्लिकेट हटाएं।
- सटीक रूप से एक बार (exactly once) का दावा करना → स्थानीय ट्रांज़ैक्शन वितरित साइड इफेक्ट्स की गारंटी नहीं दे सकते → कम से कम एक बार डिलीवरी और डाउनस्ट्रीम आइडमपोटेंसी, क्षतिपूर्ति या मानवीय प्रबंधन बताएं।
- स्वीकृति URL को प्राधिकरण मानना → रिसाव या रीप्ले पहुंच प्रदान कर सकता है → पहचान, टेनेंट, स्टेप, एक्शन, समाप्ति और एकल-उपयोग स्थिति को बांधें।
- मेमोरी में दिनों तक स्लीप करना → रीस्टार्ट और स्केलिंग प्रतीक्षा को खो देते हैं → टाइमर को बनाए रखें और शेड्यूलर के माध्यम से जगाएं।
- स्नैपशॉट को सीधे संपादित करना → रीप्ले एक अलग परिणाम उत्पन्न करता है → अधिकृत स्टेट-मशीन कमांड्स और ऑडिट इवेंट्स का उपयोग करें।
- टेनेंट्स के बीच एक कतार साझा करना → एक hot tenant दूसरों को भूखा रखता है → पार्टीशन करें, कोटा दें, प्राथमिकता दें और बैकप्रेशर लागू करें।
- नई परिभाषाओं को पुराने रन को प्रभावित करने देना → चल रहे वर्कफ़्लो समझ से बाहर हो जाते हैं → वर्ज़न्स को पिन करें और माइग्रेशन को स्पष्ट बनाएं।
अनुवर्ती प्रश्न और उत्तर
अनुवर्ती 1: गतिविधि सफल रही लेकिन परिणाम लिखने से पहले वर्कर क्रैश हो गया। क्या पुनः प्रयास दो बार चार्ज कर सकता है?
यदि डाउनस्ट्रीम सेवा एक आइडमपोटेंसी कुंजी का समर्थन करती है, तो उसी कुंजी के साथ पुनः प्रयास करें और पूर्ण परिणाम को मैप करें। अन्यथा, आंख मूंदकर पुनः प्रयास न करें: डाउनस्ट्रीम स्थिति की जांच करें, मानवीय प्रबंधन में प्रवेश करें, या क्षतिपूर्ति करें। स्टेट मशीन अपने स्वयं के इवेंट्स को सुसंगत बना सकती है, लेकिन यह अपने आप सटीक रूप से एक बार भुगतान सिमेंटिक्स नहीं बना सकती है।
अनुवर्ती 2: एक स्वीकृतकर्ता दो बार स्वीकृत (approve) पर क्लिक करता है। क्या होता है?
pending से approved तक सशर्त अपडेट या विशिष्टता बाधा के साथ एक सफल टोकन उपभोग की अनुमति दें। दूसरा अनुरोध पहले से प्रबंधित या समाप्त हो चुका लौटाता है और वर्कफ़्लो को आगे नहीं बढ़ाता है। दोनों अनुरोध और पहचानें ऑडिट ट्रेल में रहती हैं।
अनुवर्ती 3: आप "किन्हीं दो स्वीकृतकर्ताओं" का समर्थन कैसे करते हैं?
एक स्वीकृति इनबॉक्स और नीति वर्ज़न बनाए रखें। प्राधिकरण स्नैपशॉट सहित प्रति स्वीकृतकर्ता एक गैर-डुप्लिकेट निर्णय रिकॉर्ड करें। केवल तभी आगे बढ़ें जब कोरम पूरा हो जाए; अस्वीकृति, निरसन और स्वीकृतकर्ता प्रतिस्थापन स्पष्ट कमांड्स हैं।
अनुवर्ती 4: एक ऑपरेटर को तत्काल एक स्टेप को छोड़ना (skip करना) है। सुरक्षित तरीका क्या है?
पहले अधिकृत भूमिकाओं, स्किप करने योग्य स्टेप्स और सुरक्षा स्थितियों को परिभाषित करें। पुरानी स्टेट, नई स्टेट, ऑपरेटर और स्वीकृति के साथ एक तर्कसंगत StepSkipped कमांड जारी करें। यदि छोड़ना किसी व्यावसायिक नियम का उल्लंघन करता है, तो इसे अस्वीकार करें और डेटाबेस को संपादित करने के बजाय क्षतिपूर्ति या समाप्ति की पेशकश करें।
अनुवर्ती 5: आप किसी टेनेंट को असीमित वर्कफ़्लो बनाने से कैसे रोकते हैं?
प्रति टेनेंट स्टेप्स, शाखा गहराई, गतिविधि कॉन्करेंसी, इतिहास आकार, टाइमर गणना और कुल रनटाइम को सीमित करें। परिभाषाओं को स्थिर रूप से मान्य करें और निष्पादन को मापें। कोटा से अधिक होने पर असीमित वृद्धि की अनुमति देने के बजाय ऑपरेटर-दृश्यमान कारण के साथ काम को रोक दिया जाता है या अस्वीकार कर दिया जाता है।