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
দ্বারা ধরা হয়েছে ব্লক স্ট্যান্ডার্ড ত্রুটি। যদি আমরা একটি নির্দিষ্ট ক্লাসে পাস না করি, রুবি স্ট্যান্ডার্ড এরর এবং সমস্ত সাবক্লাসড ত্রুটি উদ্ধার করবে। 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৷
SignalException ব্যবহার করা হয় যখন বাইরের কোনো উৎস অ্যাপ্লিকেশনটিকে থামতে বলে। এটি অপারেটিং সিস্টেম হতে পারে যখন এটি বন্ধ করতে চায়, বা একটি সিস্টেম প্রশাসক যে অ্যাপ্লিকেশনটি বন্ধ করতে চায়। উদাহরণ
exit
হলে SystemExit ব্যবহার করা হয় রুবি অ্যাপ্লিকেশন থেকে বলা হচ্ছে. যখন এটি উত্থাপিত হয় তখন বিকাশকারী অ্যাপ্লিকেশনটি বন্ধ করতে চায়৷ উদাহরণ
যদি আমরা ব্যতিক্রম উদ্ধার করি এবং এই ব্যতিক্রমগুলি উত্থাপিত হয় যখন একটি অ্যাপ্লিকেশন বর্তমানে
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-এ আমাদের জানান। আপনি যদি আপনার অ্যাপে কোথায় এবং কতবার ব্যতিক্রমগুলি উত্থাপিত হয় সে সম্পর্কে আরও ভাল অন্তর্দৃষ্টি পেতে চাইলে, AppSignal ব্যবহার করে দেখুন৷