प्रतिनिधि इंटरव्यू विषय

फ़्रंटएंड इंटरव्यू: आप एक मज़बूत WebSocket रीकनेक्ट क्लाइंट कैसे डिज़ाइन करेंगे?

फ्रंटएंडकठिन
Offer.cc संपादकीय टीमप्रकाशित अपडेट किया गया

प्रश्न

नेटवर्क बदलने के बाद एक रीयल-टाइम कोलैबोरेशन पेज अक्सर फ्रीज़ हो जाता है और केवल रीफ़्रेश करने के बाद ही ठीक होता है। आप WebSocket क्लाइंट के लिए डिटेक्शन, रीकनेक्शन, स्टेट रिकवरी और यूज़र फ़ीडबैक को कैसे डिज़ाइन करेंगे?

प्रॉम्प्ट और संदर्भ

यह प्रश्न परीक्षण करता है कि क्या एक फ़्रंटएंड इंजीनियर WebSocket को एक अविश्वसनीय (unreliable) कनेक्शन के रूप में देखता है। वाई-फ़ाई परिवर्तन, स्लीप, प्रॉक्सी रीसेट, सर्वर रीस्टार्ट और साइलेंट हाफ़-ओपन सॉकेट्स सामान्य बात हैं। onclose से तुरंत connect() को कॉल करना एक रीकनेक्ट स्टॉर्म पैदा करता है और ऑफ़लाइन रहने के दौरान छूटे हुए इवेंट्स को पुनर्प्राप्त (recover) नहीं कर सकता है। क्लाइंट स्टेट, बैकऑफ़, हार्टबीट, रीप्ले, ऑथेंटिकेशन और पेज लाइफ़साइकिल को कवर करें।

इंटरव्यूअर क्या टेस्ट करता है

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

स्पष्ट करने योग्य प्रश्न

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

30-सेकंड उत्तर फ़्रेमवर्क

“मैं क्लाइंट को idle, connecting, open, suspect, backoff और closed स्टेट्स के साथ मॉडल करूँगा। ओपन होने के बाद, डेडलाइन वाला एप्लिकेशन ping/pong साइलेंट विफलताओं का पता लगाता है। असामान्य रूप से बंद होने या हार्टबीट टाइमआउट होने पर जिटर वाला एक्सपोनेंशियल बैकऑफ़ शुरू होता है ताकि सभी क्लाइंट्स एक साथ रीकनेक्ट न करें। प्रत्येक इवेंट में एक मोनोटोनिक सीक्वेंस होता है; रीकनेक्ट के बाद, लाइव इवेंट्स प्राप्त करने से पहले क्लाइंट अपने अंतिम निरंतर (contiguous) कर्सर से फिर से शुरू करता है। कमांड्स में इडेम्पोटेंसी (idempotency) कुंजियाँ होती हैं और उनके लिए पावती (acknowledgement) की आवश्यकता होती है, जबकि नोटिफ़िकेशन्स को ड्रॉप किया जा सकता है। ऑफ़लाइन, छिपी हुई और एक्सपायर-टोकन स्थितियाँ स्पष्ट यूज़र फ़ीडबैक के साथ रुकती हैं या फिर से प्रमाणित करती हैं।”

चरण-दर-चरण विस्तृत उत्तर

चरण 1: कनेक्शन स्टेट मशीन को परिभाषित करें

कॉलबैक्स को isConnected में बदलाव करने देने के बजाय स्टेट और वैध ट्रांज़िशन्स को केंद्रीकृत करें। एक विशिष्ट पथ connecting -> open -> suspect -> backoff -> connecting है; यूज़र द्वारा बंद करने पर closed में प्रवेश होता है और स्वचालित रीकनेक्ट अक्षम हो जाता है। प्रत्येक ट्रांज़िशन के लिए कारण, प्रयास गणना (attempt count) और कनेक्शन आईडी रिकॉर्ड करें।

चरण 2: क्लोज़, एरर और हाफ़-ओपन सॉकेट्स में अंतर करें

ब्राउज़र error इवेंट्स में कार्रवाई योग्य कारण शामिल नहीं हो सकता है, और हाफ़-ओपन पथ के लिए close कभी नहीं आ सकता है। हार्टबीट भेजने का समय, pong की अंतिम समय-सीमा (deadline) और अंतिम प्राप्त संदेश को रिकॉर्ड करता है। टाइमआउट होने पर, नया सॉकेट शेड्यूल करने से पहले पुराने सॉकेट को स्पष्ट रूप से बंद करें ताकि दो कनेक्शन डुप्लिकेट इवेंट्स डिलीवर न कर सकें।

चरण 3: बैकऑफ़ और जिटर लागू करें

RFC 6455 चेतावनी देता है कि लगातार तत्काल रीकनेक्ट करने से डिनायल-ऑफ़-सर्विस जैसा स्टॉर्म उत्पन्न हो सकता है। min(cap, base * 2^attempt) + random(0, jitter) का उपयोग करें और केवल एक स्थिर कनेक्शन के बाद ही प्रयास गणना को रीसेट करें। सर्वर रखरखाव या थ्रॉटलिंग संकेतों का सम्मान करें जैसे कि Retry-After

चरण 4: इवेंट कर्सर को पुनर्प्राप्त करें

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

चरण 5: सेंड क्यू और इडेम्पोटेंसी डिज़ाइन करें

प्रेजेंस और टाइपिंग नोटिफ़िकेशन्स को ड्रॉप किया जा सकता है; संपादन और भुगतान इंटेंट्स के लिए पावती की आवश्यकता होती है। कमांड्स में एक clientMessageId होता है, और सर्वर उस कुंजी द्वारा डिडुप्लिकेट करता है और परिणाम संग्रहीत करता है। एक सीमित (bounded) ऑफ़लाइन क्यू रखें; भर जाने पर, असीमित मेमोरी क्यू को छिपाने के बजाय अधिक कमांड्स स्वीकार करना बंद करें और स्थिति स्पष्ट करें।

चरण 6: प्रमाणीकरण और प्रोटोकॉल परिवर्तनों को संभालें

रीकनेक्ट करने से पहले जांचें कि क्या टोकन समाप्त होने वाला है और आवश्यकता पड़ने पर इसे रीफ़्रेश करें। एक अनधिकृत क्लोज़ कोड ब्लाइंड री-ट्राई को रोकता है और लॉगिन फ़्लो में प्रवेश करता है। हैंडशेक में एक प्रोटोकॉल वर्ज़न शामिल करें; हमेशा के लिए लूप करने के बजाय एक संगत वर्ज़न पर बातचीत (negotiate) करें या अपग्रेड पथ दिखाएं।

चरण 7: पेज और नेटवर्क लाइफ़साइकिल को एकीकृत करें

visibilitychange, online/offline और मोबाइल बैकग्राउंडिंग रणनीति को बदलते हैं। एक छिपा हुआ पेज हार्टबीट आवृत्ति को कम कर सकता है या लाइव डिलीवरी को रोक सकता है; वापस आने पर, एक हेल्थ चेक और कर्सर सिंक चलाएं। ऑफ़लाइन तुरंत डायलिंग बंद कर देता है और ऑनलाइन विफल प्रयासों को दोहराने के बजाय बैकऑफ़ शेड्यूल शुरू करता है।

चरण 8: उपयोगकर्ता अनुभव और सर्वर दबाव का निरीक्षण करें

कनेक्शन समय, रीकनेक्ट प्रयास, हार्टबीट टाइमआउट, रीप्ले गणना, कर्सर अंतराल और ड्रॉप किए गए क्यू आइटम रिकॉर्ड करें। सर्वर टेनेंट और क्लाइंट वर्ज़न द्वारा समवर्ती (concurrent) सॉकेट्स, हैंडशेक विफलताओं, रीकनेक्ट पीक्स और डुप्लिकेट संदेशों का निरीक्षण करता है। कभी भी टोकन या संदेश बॉडी को लॉग न करें। ट्रांसपोर्ट एरर कोड के बजाय “रीकनेक्ट हो रहा है” और “सिंक हो गया” दिखाएं।

न्यूनतम स्टेट-मशीन स्यूडोकॉड

text
on_open(socket):
    state = OPEN
    send({type: "resume", lastSeen: cursor})

on_heartbeat_timeout():
    socket.close()
    state = BACKOFF
    delay = min(MAX, BASE * 2 ** attempts) + random(0, JITTER)
    schedule(connect, delay)

ट्रेड-ऑफ़ और सीमाएं

निर्णयविकल्पकारण
रीकनेक्ट विलंबट्रंकेटेड एक्सपोनेंशियल बैकऑफ़ प्लस जिटरसिंक्रोनाइज़्ड पीक्स को कम करता है
रिकवरीकर्सर रीप्ले, आवश्यकता पड़ने पर स्नैपशॉटपेज रीफ़्रेश की आवश्यकता से बचाता है
विश्वसनीयताछोड़े जा सकने वाले नोटिफ़िकेशन्स, इडेम्पोटेंट पावती-प्राप्त कमांड्सलागत को व्यावसायिक मूल्य के साथ संरेखित करता है
बैकग्राउंड टैब्सथ्रॉटल या पॉज़, फिर लौटने पर सिंकपावर और निष्क्रिय कनेक्शन बचाता है

WebSocket क्रमित संदेश प्रदान करता है, न कि बिज़नेस-लेवल exactement-once, ऑफ़लाइन क्यूज़ या स्टेट सिंक्रोनाइज़ेशन। वे सिमेंटिक्स एप्लिकेशन प्रोटोकॉल से संबंधित हैं। यदि किसी उत्पाद को केवल लॉसी सर्वर पुश की आवश्यकता है, तो SSE की तुलना करें, लेकिन ट्रांसपोर्ट विकल्प को रिकवरी गारंटी के साथ भ्रमित न करें।

रोलआउट योजना और साक्ष्य

पहले स्टेट मशीन, हार्टबीट और जिटर वाले बैकऑफ़ को शिप करें, फिर कर्सर रिकवरी और इडेम्पोटेंट कमांड्स जोड़ें। नेटवर्क परिवर्तन, सर्वर रीस्टार्ट, ब्राउज़र स्लीप, टोकन समाप्ति और कई क्लाइंट्स के सिंक्रोनाइज़्ड डिस्कनेक्ट का अभ्यास करें। RFC 6455 असामान्य क्लोज़र के बाद रैंडम प्रारंभिक विलंब और बढ़ते बैकऑफ़ की अनुशंसा करता है; MDN ब्राउज़र WebSocket इवेंट्स और readyState का दस्तावेजीकरण करता है।

पायलट निकास मानदंड

पेज बिना रीफ़्रेश के रिकवर होता है; पावती-प्राप्त कमांड्स न तो डुप्लिकेट होते हैं और न ही खोते हैं; रीकनेक्ट पीक्स सर्वर को ओवरलोड नहीं करते हैं; छिपे हुए पेज अनावश्यक सॉकेट्स नहीं रखते हैं; और यूज़र्स कनेक्शन स्थिति और अंतिम सिंक समय देख सकते हैं। किसी भी विफलता का अर्थ है पहले प्रोटोकॉल या लाइफ़साइकिल नीति को ठीक करना।

कैसे साबित करें कि लाभ वास्तविक है

पहले और बाद में रिकवरी सफलता, p95 रिकवरी समय, डुप्लिकेट-इवेंट दर, कर्सर अंतराल, हैंडशेक पीक्स और मोबाइल ऊर्जा की तुलना करें। नेटवर्क, ब्राउज़र और पेज दृश्यता द्वारा विभाजित करें ताकि औसत किसी एक प्लेटफ़ॉर्म की विफलताओं को न छिपाए।

सामान्य गलतियाँ और फ़ॉलो-अप

onclose में तुरंत रीकनेक्ट करना

जब कोई सर्वर रीस्टार्ट होता है, तो प्रत्येक क्लाइंट एक साथ डायल करता है। बैकऑफ़, जिटर और सर्वर थ्रॉटलिंग संकेतों का उपयोग करें, और स्थिरता के बाद ही प्रयासों को रीसेट करें।

केवल close पर निर्भर रहना

हाफ़-ओपन पथ कभी भी close उत्सर्जित नहीं कर सकता है। हार्टबीट और डेडलाइन का उपयोग करें, फिर पुराने सॉकेट को स्वयं बंद करें।

यह मान लेना कि सफल रीकनेक्ट का अर्थ संपूर्ण डेटा है

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

आप डुप्लिकेट कमांड्स को कैसे रोकते हैं?

प्रत्येक कमांड को एक क्लाइंट इडेम्पोटेंसी कुंजी दें, सर्वर परिणाम को बनाए रखें, और पावती या परिणाम क्वेरी के बाद ही क्यू आइटम को हटाएं।

क्या होगा यदि रीकनेक्ट के दौरान टोकन समाप्त हो जाए?

रीफ़्रेश करें और फिर से हैंडशेक करें। एक अनधिकृत क्लोज़ रिट्राइज़ को रोकता है और लॉगिन फ़्लो में प्रवेश करता है; यह कोई क्षणिक नेटवर्क त्रुटि नहीं है।

आप टैब्स में कनेक्शन को कैसे नियंत्रित करते हैं?

BroadcastChannel या SharedWorker का उपयोग करें ताकि एक टैब सॉकेट का स्वामित्व रखे और अन्य सब्सक्राइब करें। जब मालिक गायब हो जाए तो स्वामित्व स्थानांतरित करें और कर्सर को पुन: मान्य करें।

सार्वजनिक स्रोत

संबंधित प्रश्न