त्रुटि दमन के खिलाफ तर्क


35

मुझे हमारी एक परियोजना में इस तरह का एक कोड मिला है:

    SomeClass QueryServer(string args)
    {
        try
        {
            return SomeClass.Parse(_server.Query(args));
        }
        catch (Exception)
        {
            return null;
        }
    }

जहां तक ​​मैं समझता हूं, इस तरह की त्रुटियों को दबाना एक बुरा अभ्यास है, क्योंकि यह मूल सर्वर के अपवाद से उपयोगी जानकारी को नष्ट कर देता है और कोड को जारी रखता है जब यह वास्तव में समाप्त होना चाहिए।

इस तरह की सभी त्रुटियों को पूरी तरह से दबा देना कब उचित है?


13
एरिक लिपर्ट ने एक बढ़िया ब्लॉग पोस्ट लिखा है, जिसे वेक्सिंग अपवाद कहा जाता है, जहां वह अपवादों को 4 अलग-अलग श्रेणियों में वर्गीकृत करता है और बताता है कि प्रत्येक के लिए सही दृष्टिकोण क्या है। C # परिप्रेक्ष्य से लिखा गया है लेकिन भाषाओं में लागू है, मेरा मानना ​​है।
डेमियन___बेलिवर

3
मेरा मानना ​​है कि कोड "फेल-फास्ट" सिद्धांत का उल्लंघन करता है। इस बात की प्रबल संभावना है कि इसमें वास्तविक बग छिपा हो।
जश्न


4
तुम बहुत पकड़ रहे हो। आप कीड़े को भी पकड़ रहे होंगे, जैसे कि एनआरई, सीमा सूचकांक से बाहर सीमा, कॉन्फ़िगरेशन त्रुटि, ... यह आपको उन बगों को खोजने से रोकता है और वे लगातार नुकसान पहुंचाएंगे।
usr

जवाबों:


52

पुस्तकालयों के एक समूह का उपयोग करके हजारों फ़ाइलों के साथ कोड की कल्पना करें। कल्पना कीजिए कि उन सभी को इस तरह कोडित किया गया है।

उदाहरण के लिए, अपने सर्वर के अपडेट से एक कॉन्फ़िगरेशन फ़ाइल गायब हो जाती है; और अब आपके पास एक स्टैक ट्रेस है एक अशक्त सूचक अपवाद है जब आप उस वर्ग का उपयोग करने का प्रयास करते हैं: आप इसे कैसे हल करेंगे? इसमें घंटों लग सकते हैं, जहां कम से कम बस लॉगिंग फ़ाइल के कच्चे स्टैक ट्रेस नहीं पाए जाते हैं [फ़ाइल पथ] आपको क्षण भर में हल करने में सक्षम कर सकता है।

या इससे भी बदतर: आपके द्वारा उपयोग किए जाने वाले पुस्तकालयों में से एक में असफलता बाद में आपके कोड को दुर्घटनाग्रस्त कर देती है। आप इस लाइब्रेरी को वापस कैसे ट्रैक कर सकते हैं?

बिना मजबूत त्रुटि के भी सिर्फ काम करना

throw new IllegalStateException("THIS SHOULD NOT HAPPENING")

या

LOGGER.error("[method name]/[arguments] should not be there")

आप समय के घंटे बचा सकते हैं।

लेकिन कुछ ऐसे मामले हैं जहां आप वास्तव में अपवाद को अनदेखा करना चाहते हैं और इस तरह से अशक्त हो सकते हैं (या कुछ भी नहीं)। खासकर यदि आप कुछ बुरी तरह से डिजाइन की गई विरासत कोड के साथ एकीकृत करते हैं और यह अपवाद एक सामान्य मामले के रूप में अपेक्षित है।

वास्तव में ऐसा करते समय आपको बस आश्चर्य होना चाहिए कि क्या आप वास्तव में अपनी आवश्यकताओं के लिए अपवाद या "ठीक से निपटने" की अनदेखी कर रहे हैं। यदि लौटाने वाला नल उस दिए गए मामले में आपके अपवाद को "ठीक से" संभाल रहा है, तो इसे करें। और एक टिप्पणी जोड़ें कि यह क्यों करना उचित है।

सर्वोत्तम प्रथाएँ अधिकांश मामलों में अनुसरण करने वाली चीज़ें हैं, शायद maybe०%, शायद ९९%, लेकिन आपको हमेशा एक किनारे का मामला मिलेगा जहाँ वे लागू नहीं होते हैं। उस स्थिति में, एक टिप्पणी छोड़ दें कि आप दूसरों के लिए अभ्यास का पालन क्यों नहीं कर रहे हैं (या खुद भी) जो आपके कोड महीनों बाद पढ़ेंगे।


7
+1 यह बताने के लिए कि आपको क्यों लगता है कि आपको टिप्पणी में ऐसा करने की आवश्यकता है। एक स्पष्टीकरण के बिना, अपवाद निगलने से हमेशा मेरे सिर में खतरे की घंटी उठेगी।
jpmc26

उस के साथ मेरी समस्या यह है कि टिप्पणी उस कोड के अंदर फंस गई है। फ़ंक्शन के उपभोक्ता के रूप में, मुझे वह टिप्पणी कभी नहीं मिल सकती है।
corsiKa

@ jpmc26 यदि अपवाद को संभाला जाता है (उदाहरण के लिए एक विशेष मान लौटाकर), तो वह अपवाद-निगलना नहीं है।
डेडुप्लिकेटर

2
@corsiKa एक उपभोक्ता को कार्यान्वयन विवरण को जानने की आवश्यकता नहीं है यदि फ़ंक्शन ठीक से अपना काम कर रहा है। शायद वे अपाचे पुस्तकालयों, या वसंत में इसके कुछ हैं और आप इसे नहीं जानते हैं।
वालफ्रैट

@Deduplicator हाँ, लेकिन अपने एल्गोरिथ्म के एक भाग के रूप में एक कैच का उपयोग करना एक अच्छा व्यवहार नहीं माना जाता है :)
Walfrat

14

ऐसे मामले हैं जहां यह पैटर्न उपयोगी है - लेकिन उनका उपयोग आमतौर पर तब किया जाता है जब उत्पन्न अपवाद कभी नहीं होना चाहिए (यानी जब अपवाद सामान्य परिस्थितियों के लिए उपयोग किए जाते हैं)।

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

हालाँकि, इसकी अक्सर आप ऐसा करना चाहते हैं, और यदि कोड इस तरह के पैटर्न से अटे पड़े हैं तो आप इससे निपटना चाहते हैं। बहुत कम से कम मुझे उम्मीद है कि इस तरह के एक साइलेंट कैच को लॉग लाइन लिखने के लिए कहा जाएगा कि यह क्या हुआ है (आपके पास ट्रेसिंग है, राइट) और इस व्यवहार को समझाने के लिए एक टिप्पणी।


2
"इसका उपयोग तब किया जाता है जब उत्पन्न अपवाद कभी नहीं होना चाहिए" ऐसी कोई बात नहीं है। अपवाद का सूत्र यह संकेत देना है कि कुछ गलत हुआ।
जश्न

3
@Euphoric लेकिन कभी-कभी किसी लाइब्रेरी के लेखक को उस लाइब्रेरी के अंतिम उपयोगकर्ता के इरादे नहीं पता होते हैं। एक व्यक्ति की "बुरी तरह से गलत" किसी और की आसानी से ठीक होने की स्थिति हो सकती है।
साइमन बी

2
@ कामुक, यह इस बात पर निर्भर करता है कि आपकी भाषा "बुरी तरह से गलत" क्या मानती है: पायथन लोगों को उन चीज़ों के लिए अपवाद पसंद है जो प्रवाह नियंत्रण के लिए बहुत करीब हैं (जैसे,) C ++। कुछ स्थितियों में रिटर्निंग शून्य हो सकता है - उदाहरण के लिए, कैश से पढ़ना जहां आइटम अचानक और अप्रत्याशित रूप से बेदखल हो सकते हैं।
मैट क्राउज

10
@Euphoric, "फ़ाइल नहीं मिली है, यह एक सामान्य अपवाद नहीं है। आपको सबसे पहले यह देखना चाहिए कि अगर मौजूद है तो फ़ाइल मौजूद है या नहीं।" नहीं! नहीं! नहीं! नहीं! परमाणु संचालन के आसपास क्लासिक गलत सोच है। आपके मौजूद होने और उसे एक्सेस करने की जाँच करने के बीच फ़ाइल को डिलीट किया जा सकता है। इस तरह की स्थितियों को संभालने का एकमात्र सही तरीका यह है कि यदि वे होते हैं तो अपवादों को संभालना और उन्हें संभालना है, जैसे nullकि यदि आपकी चुनी हुई भाषा सबसे अच्छी हो तो वे वापस लौट सकते हैं।
डेविड अर्नो

3
@ यूफ़ोरिक: तो, फ़ाइल को कम से कम दो बार एक्सेस करने में सक्षम नहीं करने के लिए कोड लिखें? यह DRY का उल्लंघन करता है, और गैर-पंजीकृत कोड भी टूटा हुआ कोड है।
Deduplicator

7

यह 100% संदर्भ पर निर्भर है। यदि ऐसे फ़ंक्शन के कॉलर को कहीं पर त्रुटियों को प्रदर्शित करने या लॉग करने की आवश्यकता होती है, तो यह स्पष्ट रूप से बकवास है। यदि कॉलर ने सभी त्रुटियों या अपवाद संदेशों को अनदेखा कर दिया, तो अपवाद या उसके संदेश को वापस करने के लिए बहुत अधिक समझ में नहीं आएगा। जब आवश्यकता किसी कारण को प्रदर्शित किए बिना केवल कोड को समाप्त करने की होती है, तो एक कॉल

   if(QueryServer(args)==null)
      TerminateProgram();

शायद पर्याप्त होगा। आपको यह विचार करना होगा कि क्या यह उपयोगकर्ता द्वारा त्रुटि का कारण खोजने के लिए कठिन बना देगा - यदि ऐसा है, तो यह त्रुटि हैंडलिंग का गलत रूप है। हालाँकि, यदि कॉलिंग कोड ऐसा दिखता है

  result = QueryServer(args);
  if(result!=null)
      DoSomethingMeaningful(result);
  // else ??? Mask the error and let the user run into trouble later

तब आपको कोड की समीक्षा के दौरान डेवलपर के साथ तर्क करना चाहिए। अगर कोई गैर-त्रुटि हैंडलिंग के ऐसे रूप को लागू करता है, क्योंकि वह सही आवश्यकताओं के बारे में जानने के लिए बहुत आलसी है, तो इस कोड को उत्पादन में नहीं जाना चाहिए, और कोड के लेखक को इस तरह के आलस्य के संभावित परिणामों के बारे में सिखाया जाना चाहिए ।


5

जिन वर्षों में मैंने प्रोग्रामिंग और डेवलपिंग सिस्टम को बिताया है, केवल दो ही परिस्थितियाँ हैं जहाँ मुझे प्रश्न उपयोगी में पैटर्न मिला है (दोनों ही मामलों में प्रवीण भी फेंके गए अपवाद का लॉगिंग है, मैं सादे पकड़ को नहीं मानता और nullएक अच्छी प्रैक्टिस के रूप में वापसी करता हूँ। )।

दो स्थितियां निम्नलिखित हैं:

1. जब अपवाद को एक असाधारण राज्य नहीं माना जाता था

यह तब होता है जब आप कुछ डेटा पर एक ऑपरेशन करते हैं, जो फेंक सकता है, आप जानते हैं कि यह फेंक सकता है लेकिन आप अभी भी चाहते हैं कि आपका एप्लिकेशन चालू रहे, क्योंकि आपको संसाधित डेटा की आवश्यकता नहीं है। यदि आप उन्हें प्राप्त करते हैं, तो यह अच्छा है, यदि आप नहीं करते हैं, तो यह भी अच्छा है।

किसी वर्ग की कुछ वैकल्पिक विशेषताएँ मन में आ सकती हैं।

2. जब आप एक नया (बेहतर, तेज?) प्रदान कर रहे हैं, तो पहले से ही उपयोग किए गए इंटरफ़ेस का उपयोग करके एक पुस्तकालय का उपयोग करें

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

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

आप अपने मुख्य आवेदन के अपवादों को लीक नहीं करना चाहते हैं, इसलिए आप इस नए निर्भरता को लपेटने के लिए आपके द्वारा बनाए गए एडेप्टर में उन्हें दबाते हैं और लॉग इन करते हैं।


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

मैं व्यक्तिगत रूप से अपवाद का उपयोग केवल पहले मामले के लिए करता हूं। मैंने केवल दूसरे मामले के लिए इसका उपयोग किया है, जब हमारे पास nullएस के बजाय अपवाद के साथ आवेदन के बाकी काम करने के लिए बजट नहीं था ।


-1

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

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

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

यदि यह पता चलता है कि किसी अवैध संसाधन को छोड़ने से पहले इसे इस्तेमाल करने का कोई प्रयास किया जाता है, तो इसका कोई कारण नहीं है कि इसे आवेदन को नीचे लाया जाना चाहिए। यदि किसी अमान्य संसाधन किसी अनुप्रयोग के निरंतर संचालन के लिए महत्वपूर्ण है, तो अनुप्रयोग को नीचे लाना होगा, लेकिन संसाधन को अमान्य करने से संभवतः ऐसा हो जाएगा। मूल अपवाद प्राप्त करने वाले कोड में अक्सर यह जानने का कोई तरीका नहीं होता है कि कौन सी स्थिति लागू होती है, लेकिन अगर यह संसाधन को अमान्य करता है तो यह सुनिश्चित कर सकता है कि सही कार्रवाई दोनों मामलों में की जाएगी।


2
यह प्रश्न का उत्तर देने में विफल रहता है क्योंकि अपवाद विवरण को जाने बिना किसी अपवाद को संभालना! = चुपचाप (जेनेरिक) अपवाद का उपभोग करना।
तैमूर

@Taemyr: यदि किसी फ़ंक्शन का उद्देश्य "X को संभव हो तो करना है, अन्यथा यह इंगित करें कि यह नहीं था", और X संभव नहीं था, यह अक्सर सभी प्रकार के अपवादों को सूचीबद्ध करने के लिए अव्यावहारिक होगा जो न तो कार्य करता है। न ही कॉल करने वाले को "एक्स करने के लिए संभव नहीं था" से परे की परवाह होगी। पोकेमॉन अपवाद हैंडलिंग अक्सर ऐसे मामलों में काम करने का एकमात्र व्यावहारिक तरीका है, और लगभग उतना ही बुरा नहीं होना चाहिए क्योंकि कुछ लोग बाहर निकालते हैं यदि कोड को अमान्य चीजों के बारे में अनुशासित किया जाता है जो अप्रत्याशित अपवादों से दूषित हो जाते हैं।
सुपरकैट

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

@jmoreno: जो चीजें मुश्किल करती हैं, वह यह है कि कई स्थितियों में बड़ी संख्या में अपवाद होंगे, जिनमें से कई प्रोग्रामर विशेष रूप से प्रत्याशित नहीं होंगे, जो एक समस्या को इंगित नहीं करेगा, और कुछ अपवाद, जिनमें से एक प्रोग्रामर होगा। 'विशेष रूप से प्रत्याशित, जो एक समस्या को इंगित करते हैं, और उन्हें परिभाषित करने के लिए कोई परिभाषित व्यवस्थित तरीका नहीं है। एकमात्र तरीका जो मुझे पता है कि इसके साथ पूरी तरह से निपटने के लिए है अपवादों को अमान्य चीजें हैं जो दूषित थे, इसलिए यदि वे मायने रखते हैं तो उन्हें ध्यान नहीं दिया जाता है और यदि वे कोई फर्क नहीं पड़ता है तो उन्हें नजरअंदाज कर दिया जाता है।
सुपरकैट

-2

इस तरह की त्रुटि को निगलना किसी के लिए विशेष रूप से उपयोगी नहीं है। हां, मूल कॉलर अपवाद के बारे में परवाह नहीं कर सकता है लेकिन कोई और हो सकता है

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

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


"गंभीरता से अक्रिय" - क्या आपका मतलब "गंभीर रूप से अयोग्य" था?
Esoteric स्क्रीन नाम

@EsotericScreenName एक चुनें ... ;-)
रोबी डी

-3

मैंने ऐसे उदाहरण देखे हैं जहां तृतीय-पक्ष पुस्तकालयों में संभावित रूप से उपयोगी विधियां थीं, सिवाय इसके कि वे कुछ मामलों में अपवादों को फेंकते हैं जो मेरे लिए काम करना चाहिए। मैं क्या कर सकता हूँ?

  • ठीक वैसा ही लागू करें जैसा मुझे खुद की जरूरत है। एक समय सीमा पर मुश्किल हो सकती है।
  • तृतीय-पक्ष कोड को संशोधित करें। लेकिन फिर मुझे हर अपग्रेड के साथ मर्ज संघर्ष की तलाश करनी होगी।
  • एक साधारण नल सूचक, एक बूलियन झूठा, या जो कुछ भी में अपवाद को चालू करने के लिए एक आवरण विधि लिखें।

उदाहरण के लिए, पुस्तकालय विधि

public foo findFoo() {...} 

पहला फू लौटाता है, लेकिन अगर कोई नहीं है तो यह एक अपवाद नहीं है। लेकिन मुझे जो चाहिए वह पहले फू या नल को वापस करने की एक विधि है। इसलिए मैं इसे लिखता हूं:

public foo myFindFoo() {
    try {
        return findFoo() 
    } 
    catch (NoFooException ex) {
        return null;
    }
}

साफ-सुथरा नहीं। लेकिन कभी-कभी व्यावहारिक समाधान।


1
आपका क्या मतलब है "जहां आप के लिए उन्हें काम करना चाहिए अपवाद फेंक"?
corsiKa

@corsiKa, उदाहरण जो मेरे दिमाग में आता है वे एक सूची या समान डेटा संरचना के माध्यम से खोज करने के तरीके हैं। क्या वे असफल हो जाते हैं जब वे कुछ भी नहीं पाते हैं या वे एक अशक्त मूल्य वापस करते हैं? एक अन्य उदाहरण वेटुनल तरीके हैं जो बूलियन झूठे को वापस करने के बजाय टाइमआउट पर विफल होते हैं।
ओम
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.