Computer >> कंप्यूटर >  >> प्रोग्रामिंग >> Ruby

रूबी में बचाव अपवाद:एक प्राइमर

AppSignal पर हम रूबी अनुप्रयोगों के लिए त्रुटि ट्रैकिंग प्रदान करते हैं। ऐसा करने के लिए, हम उन सभी अपवादों को पकड़ते हैं जो हमारे ऊपर फेंके जाते हैं और डेवलपर्स को सूचित करते हैं जैसे वे होते हैं।

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

बचाव अपवाद

रूबी में अपवादों को बचाकर आप कुछ गलत होने पर अपने एप्लिकेशन को क्रैश होने से रोक सकते हैं। एक begin .. rescue . के साथ जब कोई त्रुटि होती है तो आप अपने आवेदन के लिए वैकल्पिक पथ निर्दिष्ट कर सकते हैं।

begin
  File.read "config.yml"
rescue
  puts "No config file found. Using defaults."
end

यह निर्दिष्ट करना भी संभव है कि कौन से अपवादों को बचाया जाना चाहिए। अपवाद वर्ग निर्दिष्ट करते समय, इस अपवाद के सभी उपवर्गों को भी कैप्चर किया जाएगा।

begin
  File.read "config.yml"
rescue SystemCallError => e
  puts e.class # => Errno::ENOENT
  puts e.class.superclass # => SystemCallError
  puts e.class.superclass.superclass # => StandardError
end

ऊपर के उदाहरण में आप अपवाद देख सकते हैं Errno::ENOENT पकड़ा जाता है जब उसके पैरेंट SystemCallError बचाया जा रहा है।

अपवाद शृंखला में बहुत ऊपर की ओर बचाव करना

यह महत्वपूर्ण है कि अपवादों को अपवाद श्रृंखला में बहुत ऊपर तक नहीं बचाया जाए। जब आप ऐसा करते हैं, तो सभी उपवर्ग अपवाद भी पकड़े जाएंगे, जिससे बचाव ब्लॉक का कैप्चर बहुत सामान्य हो जाएगा।

यहां एक प्रोग्राम है जो प्रोग्राम को दिए गए तर्क के आधार पर एक कॉन्फ़िग फ़ाइल पढ़ता है।

# $ ruby example.rb config.yml
def config_file
  ARGV.firs # Note the typo here, we meant `ARGV.first`.
end
 
begin
  File.read config_file
rescue
  puts "Couldn't read the config file"
end

त्रुटि संदेश कहता है कि यह कॉन्फ़िग फ़ाइल को नहीं पढ़ सका, लेकिन वास्तविक समस्या कोड में एक टाइपो थी।

begin
  File.read config_file
rescue => e
  puts e.inspect
end
#<NoMethodError: undefined method `firs' for []:Array>

डिफ़ॉल्ट अपवाद वर्ग एक begin .. rescue . द्वारा पकड़ा गया ब्लॉक मानक त्रुटि है। यदि हम किसी विशिष्ट वर्ग में उत्तीर्ण नहीं होते हैं, तो रूबी StandardError और सभी उपवर्गित त्रुटियों से बचाव करेगी। NoMethodError इनमें से एक त्रुटि है।

एक विशिष्ट अपवाद वर्ग को बचाने से असंबंधित त्रुटियों को गलती से एक विफलता स्थिति का संकेत देने से रोकने में मदद मिलेगी। यह अधिक विशिष्ट कस्टम त्रुटि संदेशों की भी अनुमति देता है जो अंतिम उपयोगकर्ता के लिए अधिक सहायक होते हैं।

config_file = "config.yml"
begin
  File.read config_file
rescue Errno::ENOENT => e
  puts "File or directory #{config_file} doesn't exist."
rescue Errno::EACCES => e
  puts "Can't read from #{config_file}. No permission."
end

बचाव अपवाद

अपवाद श्रृंखला में उच्च को बचाने के लिए यह अभी भी आकर्षक हो सकता है। किसी एप्लिकेशन द्वारा उठाई जा सकने वाली सभी त्रुटियों से बचाव उसे क्रैश होने से रोकेगा। (100% अपटाइम यहाँ हम आते हैं!) हालाँकि, यह बहुत सारी समस्याएँ पैदा कर सकता है।

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

दो अपवाद जिन्हें अधिकांश एप्लिकेशन बचाव नहीं करना चाहेंगे, वे हैं SignalException और SystemExit।

<ब्लॉकक्वॉट>

सिग्नल अपवाद का उपयोग तब किया जाता है जब कोई बाहरी स्रोत एप्लिकेशन को रोकने के लिए कह रहा हो। यह ऑपरेटिंग सिस्टम हो सकता है जब वह शट डाउन करना चाहता है, या एक सिस्टम एडमिनिस्ट्रेटर जो एप्लिकेशन को रोकना चाहता है। उदाहरण

<ब्लॉकक्वॉट>

SystemExit का उपयोग तब किया जाता है जब exit रूबी आवेदन से बुलाया जा रहा है। जब यह उठाया जाता है तो डेवलपर चाहता है कि एप्लिकेशन बंद हो जाए। उदाहरण

<ब्लॉकक्वॉट>

यदि हम अपवाद को बचाते हैं और इन अपवादों को तब उठाया जाता है जब कोई एप्लिकेशन वर्तमान में चल रहा हो begin ... rescue ... end ब्लॉक करें यह बाहर नहीं निकल सकता।

सामान्य परिस्थितियों में अपवाद को बचाना आम तौर पर एक बुरा विचार है। अपवाद को बचाते समय, आप SignalException और SystemExit को कार्य करने से रोकेंगे, लेकिन कुछ नाम रखने के लिए LoadError, SyntaxError और NoMemoryError भी। इसके बजाय अधिक विशिष्ट अपवादों को बचाना बेहतर है।

परीक्षणों में विफलता

जब अपवाद को बचाया जाता है, rescue Exception => e . का उपयोग करके , आपके आवेदन के अलावा अन्य चीजें टूट सकती हैं। परीक्षण सूट वास्तव में कुछ त्रुटियों को छिपा सकता है।

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

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

# RSpec example
def foo(bar)
  bar.baz
rescue Exception => e
  puts "This test should actually fail"
  # Failure/Error: bar.baz
  #   <Double (anonymous)> received unexpected message :baz with (no args)
end
 
describe "#foo" do
  it "hides an 'unexpected message' exception" do
    bar = double(to_s: "")
    foo(bar)
  end
end

अपवादों की अपेक्षा करना

कुछ कोड अपवादों को बढ़ाने के लिए हैं। एक परीक्षण सूट में अपवाद को शांत करना संभव है ताकि परीक्षण उठाए जाने पर परीक्षण विफल न हो।

def foo
  raise RuntimeError, "something went wrong"
end
 
foo rescue RuntimeError

हालांकि, यह परीक्षण नहीं करता है कि कोई अपवाद उठाया गया था या नहीं। जब अपवाद नहीं उठाया जाता है, तो आपका परीक्षण यह नहीं बता पाएगा कि व्यवहार अभी भी सही है या नहीं।

यह कहना संभव है कि अपवाद उठाया गया है, और यदि नहीं, तो कौन सा अपवाद था।

# expecting_exceptions_spec.rb
# RSpec example
def foo
  raise NotImplementedError, "foo method not implemented"
end
 
describe "#foo" do
  it "raises a RuntimeError" do
    expect { foo }.to raise_error(RuntimeError)
  end
end
1) #foo raises a RuntimeError
   Failure/Error: expect { foo }.to raise_error(RuntimeError)

     expected RuntimeError, got #<NotImplementedError: foo method not implemented> with backtrace:
       # ./expecting_exceptions_spec.rb:4:in `foo'
       # ./expecting_exceptions_spec.rb:9:in `block (3 levels) in <top (required)>'
       # ./expecting_exceptions_spec.rb:9:in `block (2 levels) in <top (required)>'
       # ./expecting_exceptions_spec.rb:9:in `block (2 levels) in <top (required)>'

अपवाद फिर से उठाएं

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

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

File.open("/tmp/my_app.status", "w") { |f| "running" }
 
begin
  foo
rescue Exception => e
  Appsignal.add_error e
  File.open("/tmp/my_app.status", "w") { |f| "stopped" }
  raise e
end

पता नहीं क्या बचाव करें?

जैसा कि पहले उल्लेख किया गया है, यह विशिष्ट होना अच्छा है कि किन त्रुटियों से बचाव करना है।

जब आप सुनिश्चित नहीं हैं कि कोई ऑपरेशन कौन से अपवाद उठा सकता है, तो StandardError को बचाना शुरू करने के लिए एक अच्छी जगह हो सकती है। अपने कोड को विभिन्न परिदृश्यों में चलाएँ और देखें कि यह क्या अपवाद उत्पन्न करता है।

begin
  File.open('/tmp/appsignal.log', 'a') { |f| f.write "Starting AppSignal" }
rescue => e
  puts e.inspect
end
#<Errno::EACCES: Permission denied @ rb_sysopen - /tmp/appsignal.log>

हर बार जब आप एक नया अपवाद देखते हैं, तो उन अपवादों या उसके प्रासंगिक मूल वर्ग के लिए विशिष्ट बचाव मामले जोड़ें। बहुत से अपवादों को बचाने के बजाय बचाव के बारे में विशिष्ट होना बेहतर है।

begin
  file = '/tmp/appsignal.log'
  File.open(file, 'a') { |f| f.write("AppSignal started!") }
rescue Errno::ENOENT => e
  puts "File or directory #{file} doesn't exist."
rescue Errno::EACCES => e
  puts "Cannot write to #{file}. No permissions."
end
 
# Or, using the parent error class
begin
  file = '/tmp/appsignal.log'
  File.open(file, 'a')
rescue SystemCallError => e
  puts "Error while writing to file #{file}."
  puts e
end

यह रूबी में अपवादों को संभालने पर हमारे प्राइमर को समाप्त करता है। यदि आप अधिक जानना चाहते हैं, या कोई विशिष्ट प्रश्न पूछना चाहते हैं, तो हमें @AppSignal पर बताएं। यदि आप इस बारे में बेहतर जानकारी प्राप्त करना चाहते हैं कि आपके ऐप में अपवाद कहां और कितनी बार उठाए गए हैं, तो ऐपसिग्नल को आज़माएं।


  1. Pry . में अपवादों के साथ कार्य करना

    यदि आप मेरे जैसे हैं, तो आप रेल कंसोल का बहुत उपयोग करते हैं। और अब तक मुझे लगता है कि हर कोई इस बात से सहमत है कि रेल कंसोल के लिए Pry सबसे अच्छी चीज है ... ठीक है, कभी भी। बिल्ट-इन टू प्राइ कुछ बहुत ही शानदार विशेषताएं हैं जो साधारण पुराने IRB की तुलना में अपवादों के साथ काम करना बहुत आसान बनाती

  1. रूबी में कस्टम अपवाद

    रूबी में अपने स्वयं के अपवाद बनाना आसान है। बस इन चरणों का पालन करें: 1. एक नई कक्षा बनाएं अपवाद वर्ग हैं, जैसे रूबी में बाकी सब कुछ! एक नए प्रकार का अपवाद बनाने के लिए, बस एक ऐसा वर्ग बनाएं जो StandardError या उसके किसी बच्चे से विरासत में मिला हो। class MyError < StandardError end raise MyErr

  1. रूबी में अपवादों में संदर्भ डेटा कैसे जोड़ें

    कभी-कभी मानक बैकट्रैक/त्रुटि संदेश कॉम्बो पर्याप्त नहीं होता है। त्रुटि के कारण का पता लगाने के लिए कभी-कभी आपको अतिरिक्त डेटा की आवश्यकता होती है। सौभाग्य से, रूबी में करना बहुत आसान है। त्रुटि संदेश को अनुकूलित करना अपनी त्रुटियों में प्रासंगिक जानकारी जोड़ने का सबसे आसान तरीका इसे अपवाद के संदेश