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

रूबी में निष्पादन सुनिश्चित करना, विफलताओं का पुन:प्रयास करना और अपवादों को पुन:स्थापित करना

चीजें गलत होने पर वैकल्पिक कोड पथ निष्पादित करने के लिए उठाए गए अपवादों को बचाया जा सकता है, लेकिन अपवादों को संभालने के और भी तरीके हैं। AppSignal अकादमी के इस संस्करण में, हम retry पर जाएंगे और ensure कीवर्ड, और हम बचाए गए अपवादों को फिर से बढ़ाने पर विचार करेंगे।

आइए मान लें कि हम एक अविश्वसनीय वेब एपीआई के साथ संचार कर रहे हैं। इसके अलावा हर बार एक बार नीचे होने के अलावा, यह इतना धीमा है कि इसके अनुरोधों में सेकंड लग सकते हैं। हमारी लाइब्रेरी इस एपीआई पर निर्भर करती है, और हमें इसे यथासंभव लचीला बनाने की आवश्यकता है।

ensure

ensure कीवर्ड का उपयोग सुनिश्चित करने . के लिए किया जाता है अपवाद होने पर भी कोड का एक ब्लॉक चलता है।

हमारे पुस्तकालय में, हम यह सुनिश्चित करना चाहते हैं कि टीसीपी कनेक्शन Net::HTTP.start द्वारा खोला गया है बंद है, भले ही अनुरोध विफल हो जाए क्योंकि यह समय समाप्त हो गया है, उदाहरण के लिए। ऐसा करने के लिए, हम सबसे पहले अपने अनुरोध को begin . में लपेटेंगे /ensure /end खंड मैथा। कोड में ensure भाग हमेशा चलेगा, भले ही पूर्ववर्ती begin . में कोई अपवाद उठाया गया हो ब्लॉक करें।

ensure . में ब्लॉक करें, हम Net::HTTP#finish पर कॉल करके TCP कनेक्शन को बंद करना सुनिश्चित करेंगे। जब तक http वेरिएबल nil है , जो हो सकता है टीसीपी कनेक्शन खोलना विफल रहता है (जो एक अपवाद भी उठाएगा)।

require "net/http"
 
begin
  puts "Opening TCP connection..."
  http = Net::HTTP.start(uri.host, uri.port)
  puts "Sending HTTP request..."
  puts http.request_get(uri.path).body
ensure
  if http
    puts "Closing the TCP connection..."
    http.finish
  end
end

नोट :हम टीसीपी कनेक्शन को मैन्युअल रूप से बंद कर देते हैं ताकि बाद में पुन:प्रयास करते समय हमें कनेक्शन का उपयोग करने की अनुमति मिल सके। हालांकि, चूंकि Net::HTTP.start एक ब्लॉक लेता है जो यह सुनिश्चित करता है कि कनेक्शन बंद है, ऊपर दिए गए नमूने को ensure को हटाने के लिए फिर से लिखा जा सकता है . दिलचस्प बात यह है कि यह सुनिश्चित करने वाला ब्लॉक भी है कि इसे नेट ::एचटीटीपी में कैसे लागू किया जाता है।

retry

retry कीवर्ड एक ब्लॉक में कोड के एक टुकड़े को पुनः प्रयास करने की अनुमति देता है। एक rescue . के साथ संयुक्त ब्लॉक, यदि हम कनेक्शन खोलने में विफल रहते हैं, या एपीआई को प्रतिक्रिया देने में बहुत अधिक समय लगता है, तो हम इसे फिर से प्रयास करने के लिए उपयोग कर सकते हैं।

ऐसा करने के लिए, हम एक read_timeout जोड़ देंगे Net::HTTP.start . पर कॉल जो टाइमआउट को 10 सेकंड पर सेट करता है। अगर हमारे अनुरोध का जवाब तब तक नहीं आया है, तो यह एक Net::ReadTimeout उठाएगा ।

हम Errno::ECONNREFUSED . पर भी मिलान करेंगे एपीआई को पूरी तरह से डाउन होने से निपटने के लिए, जो हमें टीसीपी कनेक्शन खोलने से रोकेगा। उस स्थिति में, http वेरिएबल nil है ।

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

require "net/http"
 
http = nil
uri = URI("https://localhost:4567/")
 
begin
  unless http
    puts "Opening TCP connection..."
    http = Net::HTTP.start(uri.host, uri.port, read_timeout: 10)
  end
  puts "Executing HTTP request..."
  puts http.request_get(uri.path).body
rescue Errno::ECONNREFUSED, Net::ReadTimeout => e
  puts "Timeout (#{e}), retrying in 1 second..."
  sleep(1)
  retry
ensure
  if http
    puts "Closing the TCP connection..."
    http.finish
  end
end

अब, जब तक कोई Net::ReadTimeout . नहीं होगा, हमारा अनुरोध हर सेकेंड में फिर से प्रयास करेगा उठाया जाता है।

$ ruby retry.rb
Opening TCP connection...
Executing HTTP request...
Timeout (Net::ReadTimeout), retrying in 1 second...
Executing HTTP request...
Timeout (Net::ReadTimeout), retrying in 1 second...
Executing HTTP request...
Timeout (Net::ReadTimeout), retrying in 1 second...
Executing HTTP request...
... (in an endless loop)

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

छोड़ देना:raise . का उपयोग करके अपवादों को फिर से बढ़ाना

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

begin
  raise "Exception!"
rescue RuntimeError => e
  puts "Exception happened: #{e}"
  raise e
end

चूंकि हमारे पास rescue . में अपवाद वस्तु तक पहुंच है ब्लॉक, हम कंसोल या त्रुटि मॉनिटर में त्रुटि लॉग कर सकते हैं। वास्तव में, ऐपसिग्नल के एकीकरण त्रुटियों को ट्रैक करने का तरीका ठीक उसी तरह से है जैसे बचाव और पुनर्व्यवस्थित करना।

नोट :रूबी अंतिम उठाए गए अपवाद को $! . नामक एक चर में संग्रहीत करता है , और raise कीवर्ड डिफ़ॉल्ट रूप से इसका उपयोग करेगा। कॉल करना raise बिना किसी तर्क के अंतिम अपवाद को फिर से उठाया जाएगा।

हमारे पुस्तकालय में, हम कुछ पुनर्प्रयासों के बाद एपीआई के दबाव को लेने के लिए पुनरावर्तन का उपयोग कर सकते हैं। ऐसा करने के लिए, हम retries में अपने द्वारा किए गए पुन:प्रयासों की संख्या का ट्रैक रखेंगे। चर।

जब भी कोई समयबाह्य होता है, हम संख्या बढ़ाएंगे और जांचेंगे कि क्या यह तीन से कम या उसके बराबर है, क्योंकि हम अधिक से अधिक तीन पुन:प्रयास करना चाहते हैं। अगर ऐसा है, तो हम retry . अगर नहीं, तो हम raise पिछले अपवाद को फिर से बढ़ाने के लिए।

require "net/http"
 
http = nil
uri = URI("https://localhost:4567/")
retries = 0
 
begin
  unless http
    puts "Opening TCP connection..."
    http = Net::HTTP.start(uri.host, uri.port, read_timeout: 1)
  end
  puts "Executing HTTP request..."
  puts http.request_get(uri.path).body
rescue Errno::ECONNREFUSED, Net::ReadTimeout => e
  if (retries += 1) <= 3
    puts "Timeout (#{e}), retrying in #{retries} second(s)..."
    sleep(retries)
    retry
  else
    raise
  end
ensure
  if http
    puts 'Closing the TCP connection...'
    http.finish
  end
end

retries . का उपयोग करके कॉल में परिवर्तनशील sleep , हम हर नए प्रयास के लिए प्रतीक्षा समय बढ़ा सकते हैं।

$ ruby reraise.rb
Opening TCP connection...
Executing HTTP request...
Timeout (Net::ReadTimeout), retrying in 1 second(s)...
Executing HTTP request...
Timeout (Net::ReadTimeout), retrying in 2 second(s)...
Executing HTTP request...
Timeout (Net::ReadTimeout), retrying in 3 second(s)...
Executing HTTP request...
Closing the TCP connection...
/lib/ruby/2.4.0/net/protocol.rb:176:in `rbuf_fill': Net::ReadTimeout (Net::ReadTimeout)
...
from reraise.rb:13:in `<main>'

कोड छोड़ने से पहले हमारे अनुरोध का तीन बार पुन:प्रयास किया जाता है और अंतिम त्रुटि को फिर से उठाया जाता है। फिर हम त्रुटि को एक स्तर ऊपर संभाल सकते हैं, या हमारे ऐप को क्रैश कर सकते हैं यदि यह एपीआई की प्रतिक्रिया के बिना अपना काम पूरा नहीं कर सकता है।

एक लचीला वेब API क्लाइंट

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

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


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

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

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

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

  1. लॉगर और लॉगरेज के साथ रूबी में लॉगिंग

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