सुरंग मरते समय भी आपका एप्लिकेशन काम करता रहता है। Wi-Fi अभी चालू है, इंटरनेट अभी जवाब दे रहा है, और एप्लिकेशन जिस निजी API पर निर्भर है वह अगम्य हो गया है। लोग यहाँ आम तौर पर जिस .NET ईवेंट की ओर जाते हैं, NetworkAvailabilityChanged, वह उस स्थिति का बिल्कुल वर्णन नहीं करता। वह मशीन की समग्र स्थिति में बदलाव की सूचना देता है, और VPN डिस्कनेक्ट व पुनः कनेक्ट के दौरान भी वह स्थिति सही रह सकती है। ऑब्ज़र्वर को उस क्लाइंट को देखना चाहिए जो सुरंग का मालिक है, नेटवर्क स्टैक के सारांश को नहीं।

उपलब्धता एक समग्र मान है, आपकी सुरंग नहीं

NetworkAvailabilityChanged तब सक्रिय होता है जब मशीन का समग्र उपलब्धता उत्तर बदलता है, और वह उत्तर loopback या सुरंग के अलावा हर सक्रिय इंटरफ़ेस को गिनता है।

Wi-Fi चालू रहते VPN के गिरने से वह जो मापता है उसमें कुछ नहीं बदलता, इसलिए जिस विफलता की आपको चिंता है ठीक उसी दौरान ईवेंट शांत रह सकता है।

स्टेट स्ट्रीम सुरंग के मालिक क्लाइंट की है

पहचानें कि कौन-सा घटक कनेक्शन का मालिक है: OpenVPN GUI या सेवा, OpenVPN Connect, या वह प्रक्रिया जिसे आपके एप्लिकेशन ने शुरू किया और नियंत्रित करता है। ये अलग-अलग मालिक हैं जिनके अलग समर्थित इंटरफ़ेस हैं, और ऑब्ज़र्वर को वही इस्तेमाल करना चाहिए जो परिनियोजन से मेल खाता हो। जिस OpenVPN प्रक्रिया के साथ एकीकृत होने का आपको अधिकार है, उसके लिए प्रबंधन इंटरफ़ेस वर्तमान स्थिति, इतिहास और रीयल-टाइम सूचनाएँ बताता है। स्थानीयकृत GUI कैप्शन में connected शब्द खोजने के बजाय दस्तावेज़ित संरचित संदेशों का विश्लेषण करें।

प्रबंधन चैनल एक विशेषाधिकार प्राप्त नियंत्रण सतह है, इसलिए नया श्रोता न खोलें और GUI से उस चैनल के लिए न लड़ें जो उसके पास पहले से है।

जनरेशन गार्ड पुराने परिणाम रोकते हैं

हर अवलोकन किसी विशिष्ट कनेक्शन प्रयास का होता है। नया प्रयास शुरू होने, चैनल खोने और क्लाइंट के बाहर निकलने की सूचना देने पर जनरेशन काउंटर बढ़ाएँ।

A कनेक्शन के दौरान शुरू हुई एक जाँच को लें। सुरंग गिरती है, B कनेक्शन शुरू होता है, और फिर A की विलंबित HTTP सफलता आती है। गार्ड के बिना वह पुराना परिणाम डिस्प्ले को हरा कर देता है जबकि B अभी प्रमाणित हो रहा है। रद्द करने से बेकार काम घटता है, और जनरेशन जाँच ही उसे रोकती है कि पुराना पूरा होना वर्तमान स्थिति न बने:

var generation = _generation;
var reachable = await ProbeAsync(token);
if (generation != _generation) return;
Publish(reachable);

UI प्रेषण के आसपास भी वही नियम लागू करें, क्योंकि मार्शल किया गया अपडेट जनरेशन आगे बढ़ने के बाद भी आ सकता है।

इनिशियलाइज़ेशन और पुनः कनेक्ट एक ही जीवनचक्र हैं

पहले कनेक्शन, पुनः कनेक्ट और चैनल हानि को एक ही नियम-समूह के साथ एक ही जीवनचक्र मानें:

  • जहाँ इंटरफ़ेस अनुमति दे वहाँ एक ही चरण में वर्तमान स्थिति पढ़ें और सूचनाओं की सदस्यता लें।
  • हर अवलोकन को कनेक्शन पहचान और जनरेशन से चिह्नित करें।
  • पुनः कनेक्ट, बाहर निकलने या अवलोकन चैनल खोने पर तैयारी अमान्य करें।
  • निजी संसाधन की जाँच तभी करें जब मालिक इनिशियलाइज़ेशन पूरा होने की सूचना दे।
  • केवल वे परिणाम प्रकाशित करें जो अभी भी वर्तमान जनरेशन के हैं।

चैनल खोना अज्ञात है, डिस्कनेक्ट नहीं। अज्ञात बताना उस डिस्कनेक्ट से अधिक ईमानदार है जिसे आप साबित नहीं कर सकते, और यह पुनः प्रयास तर्क को अनुमान पर काम करने से रोकता है।

साक्ष्य बताएँ, बूलियन नहीं

नामित सत्र स्थिति और संसाधन तैयारी को अलग-अलग मान के रूप में लौटाएँ, हर एक के साथ आयु। जिसे कुछ तय करना है वह तब देख सकता है कि अंतिम सफल जाँच चालीस सेकंड पुरानी है, जो ताज़ा जानकारी से अलग जानकारी है।

सार्वजनिक IP खोज इस बात का साक्ष्य नहीं है कि किसी निजी API ने आवश्यक मार्ग इस्तेमाल किया, इसलिए इसे वैसा प्रस्तुत न करें जैसे हो।

प्रवर्तन को ऑब्ज़र्वर के बाहर रखें

कॉलबैक घटना के बाद चलता है। यह गारंटी नहीं दे सकता कि घटना और हैंडलर के बीच मशीन से कोई पैकेट नहीं निकला। अगर डिज़ाइन में अवरोधन चाहिए, तो नेटवर्किंग नीति को वह देना होगा, और ऑब्ज़र्वर का काम अपने कॉलर को साक्ष्य समझाना है। दोनों को मिलाने से ऐसा कोड बनता है जो बूलियन रखने के कारण खुद को फ़ायरवॉल मानता है। प्रवर्तन परत को उबाऊ और परीक्षण-योग्य रखें, और ऑब्ज़र्वर को पाठक बने रहने दें।

फिर UI का सवाल सरल हो जाता है: जो ज्ञात है उसे उसकी आयु के साथ दिखाएँ, और जब अज्ञात हो तो अज्ञात कहें।

संबंधित लेख