රයන් ඩේවිස්ගේ රූබි ක්වික් රීෆ් පවසයි (පැහැදිලි කිරීමකින් තොරව):
ව්යතිරේකය ගලවා නොගන්න. කවදාවත්. නැත්නම් මම ඔයාට පිහියෙන් ඇනගන්නම්.
ඇයි නැත්තේ? කළ යුතු නිවැරදි දේ කුමක්ද?
රයන් ඩේවිස්ගේ රූබි ක්වික් රීෆ් පවසයි (පැහැදිලි කිරීමකින් තොරව):
ව්යතිරේකය ගලවා නොගන්න. කවදාවත්. නැත්නම් මම ඔයාට පිහියෙන් ඇනගන්නම්.
ඇයි නැත්තේ? කළ යුතු නිවැරදි දේ කුමක්ද?
Answers:
TL; DR : StandardError
සාමාන්ය ව්යතිරේක ඇල්ලීම සඳහා ඒ වෙනුවට භාවිතා කරන්න . මුල් ව්යතිරේකය නැවත මතු කළ විට (උදා: ව්යතිරේකය ලොග් කිරීම සඳහා පමණක් ගලවා ගැනීමේදී), බේරා ගැනීම Exception
බොහෝ විට හරි ය.
Exception
මුල රූබි ගේ හැර ධුරාවලියේ , මේ වන විට ඔබ rescue Exception
ඔබ ගලවා සියල්ල වැනි උප වර්ගිකරණයන් ඇතුළු SyntaxError
, LoadError
හා Interrupt
.
ගලවා Interrupt
ගැනීමෙන් පරිශීලකයා CTRLCවැඩසටහනෙන් පිටවීම භාවිතා කිරීම වළක්වයි .
ගලවා ගැනීම SignalException
මඟින් වැඩසටහනට නිවැරදිව සං als ා වලට ප්රතිචාර දැක්වීම වළක්වයි. හැරෙන්නට එය නුසුදුසු වනු ඇත kill -9
.
ගලවා ගැනීම SyntaxError
යන්නෙන් අදහස් කරන්නේ eval
අසමත් වූ අය නිහ .ව එසේ කරනු ඇති බවයි.
මෙම වැඩසටහන ක්රියාත්මක කිරීමෙන් සහ ඒ සඳහා උත්සාහ කිරීමෙන් CTRLCහෝ kill
ඒ සියල්ල පෙන්විය හැකිය :
loop do
begin
sleep 1
eval "djsakru3924r9eiuorwju3498 += 5u84fior8u8t4ruyf8ihiure"
rescue Exception
puts "I refuse to fail or be stopped!"
end
end
සිට ගලවා ගැනීම Exception
සුපුරුදු නොවේ. කිරීම
begin
# iceberg!
rescue
# lifeboats
end
එයින් ගලවා ගන්නේ නැත Exception
, එයින් ගලවා ගනී StandardError
. ඔබ සාමාන්යයෙන් පෙරනිමියට වඩා විශේෂිත යමක් සඳහන් කළ යුතුය StandardError
, නමුත් එයින් ගලවා ගැනීම විෂය පථය පටු කරනවාට වඩා Exception
පුළුල් කරයි, විනාශකාරී ප්රති results ල ලබා ගත හැකි අතර දෝෂ දඩයම් කිරීම අතිශයින් දුෂ්කර වේ.
ඔබට ගලවා ගැනීමට අවශ්ය තත්වයක් තිබේ නම් StandardError
සහ ව්යතිරේකය සමඟ ඔබට විචල්යයක් අවශ්ය නම්, ඔබට මෙම පෝරමය භාවිතා කළ හැකිය:
begin
# iceberg!
rescue => e
# lifeboats
end
එය සමාන වේ:
begin
# iceberg!
rescue StandardError => e
# lifeboats
end
එයින් ගැලවීම Exception
පහසු වන පොදු අවස්ථා කිහිපයෙන් එකක් වන්නේ ලොග් වීම / වාර්තා කිරීම සඳහා වන අතර, එවැනි අවස්ථාවකදී ඔබ වහාම ව්යතිරේකය නැවත මතු කළ යුතුය:
begin
# iceberg?
rescue Exception => e
# do some logging
raise # not enough lifeboats ;)
end
Throwable
ජාවා අල්ලා ගැනීම වැනි ය
ADAPTER_ERRORS = [::ActiveRecord::StatementInvalid, PGError, Mysql::Error, Mysql2::Error, ::ActiveRecord::JDBCError, SQLite3::Exception]
පසුවrescue *ADAPTER_ERRORS => e
මෙම සැබෑ නීතිය: දෝ ව්යතිරේක විසි නැහැ. ඔබේ උපුටා දැක්වීමේ කතුවරයාගේ වාස්තවිකතාව සැක සහිත ය, එය අවසන් වන බවට සාක්ෂියකි
නැත්නම් මම ඔයාට පිහියෙන් ඇනගන්නම්
ඇත්ත වශයෙන්ම, සං als ා (පෙරනිමියෙන්) ව්යතිරේකයන් විසි කරන බව මතක තබා ගන්න, සාමාන්යයෙන් දිගුකාලීන ක්රියාදාමයන් සං signal ාවක් හරහා අවසන් වන බැවින් ව්යතිරේකය අල්ලා ගැනීම සහ සං signal ා ව්යතිරේකයන් අවසන් නොකිරීම ඔබේ වැඩසටහන නැවැත්වීමට ඉතා අපහසු වනු ඇත. එබැවින් මෙය නොකරන්න:
#! /usr/bin/ruby
while true do
begin
line = STDIN.gets
# heavy processing
rescue Exception => e
puts "caught exception #{e}! ohnoes!"
end
end
නැහැ, ඇත්තෙන්ම එය නොකරන්න. එය ක්රියාත්මක වේදැයි බැලීමට එය ධාවනය නොකරන්න.
කෙසේ වෙතත්, ඔබ සතුව නූල් සේවාදායකයක් ඇති බවත්, සියලු ව්යතිරේකයන් නොකිරීමට ඔබට අවශ්ය බවත් පවසන්න:
thread.abort_on_exception = true
). ඔබගේ සම්බන්ධතා හැසිරවීමේ නූලෙන් මෙය සම්පූර්ණයෙන්ම පිළිගත හැකිය:
begin
# do stuff
rescue Exception => e
myLogger.error("uncaught #{e} exception while handling connection: #{e.message}")
myLogger.error("Stack trace: #{backtrace.map {|l| " #{l}\n"}.join}")
end
ඉහත දැක්වෙන්නේ රූබිගේ පෙරනිමි ව්යතිරේක හසුරුවන්නාගේ විචල්යතාවයට අනුව ය, එය ඔබේ වැඩසටහන ද විනාශ නොකරයි. රේල්ස් සිය ඉල්ලීම් හසුරුවන්නා තුළ මෙය කරයි.
ප්රධාන ත්රෙඩ් එකේ සං al ා ව්යතිරේක මතු වේ. පසුබිම් නූල් ඒවා ලබා නොගනී, එබැවින් ඒවා අල්ලා ගැනීමට උත්සාහ කිරීමෙන් පලක් නැත.
නිෂ්පාදන පරිසරයක් තුළ මෙය විශේෂයෙන් ප්රයෝජනවත් වේ, යම් දෙයක් වැරදී ගිය විට ඔබේ වැඩසටහන සරලව නතර වීමට ඔබට අවශ්ය නැත . එවිට ඔබට ඔබේ ල logs ු-සටහන් වල ඇති කුණු කසළ රැගෙන විශේෂිත ව්යතිරේකයක් සමඟ ඇමතුම් දාමයට පහළින් හා වඩාත් අලංකාර ලෙස කටයුතු කිරීමට ඔබේ කේතයට එක් කළ හැකිය.
තවත් සමාන රූබි මෝඩයක් ඇති බව සලකන්න.
a = do_something rescue "something else"
මෙම රේඛාවේදී, do_something
ව්යතිරේකයක් මතු කරන්නේ නම් , එය රූබි විසින් අල්ලා, විසි කර, a
පවරනු "something else"
ලැබේ.
සාමාන්යයෙන්, කරදර නොවන්නැයි ඔබ දන්නා විශේෂ අවස්ථා හැර, එසේ නොකරන්න . එක් උදාහරණයක්:
debugger rescue nil
මෙම debugger
කාර්යය ඔබගේ කේතය දී කැඩුම් ඇති කිරීමට විදියේ ක්රමයක්, නමුත් ඩිබගර් පිටත ධාවනය නම්, හා රේල් පීලි, එය හැර මතු කරයි. දැන් න්යායාත්මකව ඔබ ඔබේ වැඩසටහනේ නිදොස් කිරීමේ කේතය තබා නොගත යුතුය (pff! කිසිවෙකු එසේ නොකරයි!) නමුත් යම් හේතුවක් නිසා එය ටික වේලාවක් එහි තබා ගැනීමට ඔබට අවශ්ය විය හැකිය, නමුත් ඔබේ නිදොස්කරණය නොකඩවා ක්රියාත්මක නොකරන්න.
සටහන:
සං signal ා ව්යතිරේකයන් හසුකර ඒවා නොසලකා හරින වෙනත් කෙනෙකුගේ වැඩසටහනක් ඔබ ක්රියාත්මක කරන්නේ නම් (ඉහත කේතය කියන්න) එවිට:
pgrep ruby
, හෝ ps | grep ruby
, ඔබේ වැරදි කරන වැඩසටහනේ PID සොයා බලා ධාවනය කරන්න kill -9 <PID>
. ඔබ වෙනත් කෙනෙකුගේ වැඩ සටහනක් සමඟ වැඩ කරන්නේ නම්, කුමන හේතුවක් නිසා හෝ මෙම නොසලකා හැරීම්-ව්යතිරේක කොටස් සමඟ ගම්මිරිස් කර තිබේ නම්, මෙය ප්රධාන රේඛාවේ මුදුනේ තැබීම හැකි එක් පිටවීමක් වේ:
%W/INT QUIT TERM/.each { |sig| trap sig,"SYSTEM_DEFAULT" }
මෙමඟින් වැඩසටහන අවසන් කිරීමේ සං als ාවලට ප්රතිචාර දැක්වීම ක්ෂණිකව අවසන් කිරීම, ව්යතිරේක හසුරුවන්නන් මඟ හැරීම, පිරිසිදු කිරීමකින් තොරව සිදු කරයි. එබැවින් එය දත්ත නැතිවීමට හෝ ඊට සමාන විය හැකිය. පරෙස්සම් වෙන්න!
ඔබට මෙය කිරීමට අවශ්ය නම්:
begin
do_something
rescue Exception => e
critical_cleanup
raise
end
ඔබට සැබවින්ම මෙය කළ හැකිය:
begin
do_something
ensure
critical_cleanup
end
දෙවන අවස්ථාවෙහිදී, critical cleanup
ව්යතිරේකයක් විසි කළත් නැතත් සෑම අවස්ථාවකම කැඳවනු ලැබේ.
kill -9
.
ensure
ව්යතිරේකයක් මතු වී ඇත්ද යන්න නොසලකා එය ක්රියාත්මක වන අතර rescue
කැමැත්ත ක්රියාත්මක වන්නේ ව්යතිරේකයක් මතු වුවහොත් පමණි.
නැහැ rescue Exception => e
(සහ-දියුණූ නැවත හැර නැත) - හෝ ඔබ විය හැකි පාලමක් පන්දු.
අපි කියමු ඔබ කාර් එකක (රූබි ධාවනය). ඔබ මෑතකදී නව සුක්කානම් රෝදයක් ස්ථාපනය කර ඇත (එය භාවිතා කරයි eval
), නමුත් එක් ක්රමලේඛකයෙකු සින්ටැක්ස් මත අවුල් වී ඇති බව ඔබ දැන සිටියේ නැත.
ඔබ සිටින්නේ පාලමක වන අතර, ඔබ රේල් පීල්ල දෙසට මඳක් යන බව වටහා ගන්න, එවිට ඔබ වමට හැරෙන්න.
def turn_left
self.turn left:
end
අපොයි! එය හොඳ නැත luck, වාසනාවකට මෙන්, රූබි මතු කරයි a SyntaxError
.
කාර් එක වහාම නැවැත්විය යුතුයි - හරිද?
නෑ.
begin
#...
eval self.steering_wheel
#...
rescue Exception => e
self.beep
self.log "Caught #{e}.", :warn
self.log "Logged Error - Continuing Process.", :info
end
බීප් බීප්
අවවාදයයි: අල්ලා ගත් සින්ටැක්ස් දෝෂ ව්යතිරේකය.
තොරතුරු: ලොග් වූ දෝෂය - අඛණ්ඩ ක්රියාවලිය.
ඔබට යමක් වැරදි බව ඔබ දකිනවා නම්, ඔබ හදිසි විරාම මත වැසෙන ( ^C
: Interrupt
)
බීප් බීප්
අවවාදයයි: බාධා කිරීම් ව්යතිරේකය.
තොරතුරු: ලොග් වූ දෝෂය - අඛණ්ඩ ක්රියාවලිය.
ඔව් - එය එතරම් උදව් කළේ නැත. ඔබ දුම්රියට ඉතා ආසන්නයි, එබැවින් ඔබ මෝටර් රථය උද්යානයේ තබන්න ( kill
ing :) SignalException
.
බීප් බීප්
අවවාදයයි: අල්ලා ගත් සං Sign ා එක්සෙප්ෂන් ව්යතිරේකය.
තොරතුරු: ලොග් වූ දෝෂය - අඛණ්ඩ ක්රියාවලිය.
අන්තිම තත්පරයේ දී, ඔබ යතුරු ( kill -9
) ඉවත් කර, මෝටර් රථය නවත්වන විට, ඔබ සුක්කානම ඉදිරියට තල්ලු කරයි (ඔබ වැඩසටහන ඉතා අලංකාර ලෙස නතර නොකළ නිසා එයාර් බෑගයට උඩුගත කළ නොහැක - ඔබ එය අවසන් කළා), සහ පරිගණකය ඔබේ මෝටර් රථයේ පිටුපස අසුන ඉදිරිපිට අසුනට වැටේ. අඩක් පිරී ඇති කෝක් ටින් එකක් කඩදාසි පුරා විසිරී යයි. පිටුපස ඇති සිල්ලර බඩු තලා ඇති අතර බොහෝ ඒවා බිත්තර කහ මදය සහ කිරි වලින් ආවරණය වී ඇත. මෝටර් රථයට බරපතල අලුත්වැඩියාවක් සහ පිරිසිදු කිරීමක් අවශ්ය වේ. (දත්ත නැතිවීම)
ඔබට රක්ෂණයක් (උපස්ථ) ඇතැයි බලාපොරොත්තු විය හැකිය. ඔව් - එයාර් බෑගය පුපුරා නොගිය නිසා, ඔබට බොහෝ විට රිදෙනවා (වෙඩි තැබීම, ආදිය).
නමුත් ඉන්න! තියෙනවාතවත්ඔබට භාවිතා කිරීමට අවශ්ය වීමට හේතු rescue Exception => e
!
අපි කියමු ඔබ එම මෝටර් රථය, සහ මෝටර් රථය එහි ආරක්ෂිත නැවතුම් වේගය ඉක්මවා ඇත්නම් එයාර් බෑගය උඩුගත කරන බවට වග බලා ගන්න.
begin
# do driving stuff
rescue Exception => e
self.airbags.inflate if self.exceeding_safe_stopping_momentum?
raise
end
රීතියට ව්යතිරේකය මෙන්න: ඔබට අල්ලා ගත Exception
හැක්කේ ඔබ ව්යතිරේකය නැවත මතු කළහොත් පමණි . එබැවින්, වඩා හොඳ රීතියක් වන්නේ කිසි විටෙකත් ගිල නොදැමීම Exception
සහ සෑම විටම දෝෂය නැවත මතු කිරීමයි.
නමුත් ගලවා ගැනීම එකතු කිරීම රූබි වැනි භාෂාවකින් අමතක කිරීම පහසුය, සහ ප්රශ්නයක් නැවත මතු කිරීමට පෙර ගලවා ගැනීමේ ප්රකාශයක් තැබීම ඩ්රයි නොවන බව දැනේ. තවද එම ප්රකාශය අමතක කිරීමට ඔබට අවශ්ය නැතraise
. ඔබ එසේ කරන්නේ නම්, එම දෝෂය සොයා ගැනීමට උත්සාහ කිරීම වාසනාවකි.
ස්තූතියි, රූබි නියමයි, ඔබට යතුරුපදය භාවිතා කළ හැකිය ensure
, එමඟින් කේතය ක්රියාත්මක වන බවට සහතික වේ. මෙම ensure
මූල පදය කුමක් වුවත් කේතය ධාවනය වනු ඇත - ව්යතිරේකයක් ලෝකයේ අන්ත (හෝ වෙනත් නොහැක්කකි සිදුවීම්) නම් එකම ව්යතිරේකය වීම එක් කෙනෙක් නොවේ නම්, දමන නම්,.
begin
# do driving stuff
ensure
self.airbags.inflate if self.exceeding_safe_stopping_momentum?
end
උත්පාතය! එම කේතය කෙසේ හෝ ක්රියාත්මක විය යුතුය. ඔබ භාවිතා කළ යුතු එකම හේතුව rescue Exception => e
වන්නේ ඔබට ව්යතිරේකයට ප්රවේශය අවශ්ය නම් හෝ ව්යතිරේකයක් මත කේතය ක්රියාත්මක කිරීමට අවශ්ය නම් පමණි. දෝෂය නැවත මතු කිරීමට මතක තබා ගන්න. සෑම විට.
සටහන: ialNiall පෙන්වා දුන් පරිදි, සෑම විටම ධාවනය වන බවට සහතික වන්න . මෙය හොඳ නිසා සමහර විට ඔබේ වැඩසටහන ඔබට බොරු කීමට ඉඩ ඇති අතර ගැටළු ඇති වූවත් ව්යතිරේකයන් විසි නොකරයි. එයාර් බෑග් පුපුරවා හැරීම වැනි තීරණාත්මක කාර්යයන් සමඟ, එය කුමක් වුවත් එය සිදු වන බවට ඔබ සහතික විය යුතුය. මේ නිසා, මෝටර් රථය නවත්වන සෑම අවස්ථාවකම, ව්යතිරේකයක් විසි වී ඇත්දැයි පරීක්ෂා කිරීම හොඳ අදහසකි. බොහෝ ක්රමලේඛන සන්දර්භය තුළ එයාර් බෑග් පුපුරවා හැරීම තරමක් අසාමාන්ය කාර්යයක් වුවද, බොහෝ පිරිසිදු කිරීමේ කාර්යයන් සමඟ මෙය සැබවින්ම සුලභ ය.
ensure
විකල්පයක් ලෙස rescue Exception
කොටස නොමඟ යවන සුළුය - උදාහරණයෙන් ඇඟවෙන්නේ ඒවා සමාන බවයි, නමුත් ප්රකාශ ensure
කර ඇති පරිදි ව්යතිරේකයක් තිබේද නැද්ද යන්න සිදුවනු ඇත, එබැවින් කිසිවක් වැරදී නොතිබුණද ඔබ පැයට සැතපුම් 5 ඉක්මවා ගිය නිසා දැන් ඔබේ ගුවන් ගමන් මලු පුපුරා යනු ඇත.
මෙය සියලු ව්යතිරේකයන් ග්රහණය කර ගන්නා බැවිනි. ඔබගේ වැඩසටහනට ඒවායින් කිසිවක් ලබා ගත හැකි යැයි සිතිය නොහැක .
ඔබ හැසිරවිය යුත්තේ ඔබ අයකර ගන්නේ කෙසේදැයි දන්නා ව්යතිරේක පමණි. ඔබ යම් ආකාරයක ව්යතිරේකයක් අපේක්ෂා නොකරන්නේ නම්, එය හසුරුවන්න එපා, හයියෙන් කඩා වැටෙන්න (ලොගයට විස්තර ලියන්න), පසුව ල logs ු-සටහන් හඳුනාගෙන කේතය සවි කරන්න.
ව්යතිරේකයන් ගිල දැමීම නරක ය, මෙය නොකරන්න.
එය හැසිරවිය යුතු ආකාරය ඔබ නොදන්නා කිසිදු ව්යතිරේකයක් අල්ලා නොගත යුතුය යන නීතියේ නිශ්චිත අවස්ථාවකි . ඔබ එය හැසිරවිය යුතු ආකාරය නොදන්නේ නම්, පද්ධතියේ වෙනත් කොටසක් අල්ලා එය හැසිරවීමට ඉඩ දීම සැමවිටම හොඳය.
මම ඒ ගැන හොඳ බ්ලොග් සටහනක් හනිබැඩ්ජර්.ඕ හි කියෙව්වා :
ඔබ ව්යතිරේකය ගලවා නොගත යුත්තේ ඇයි
ව්යතිරේකය ගලවා ගැනීමේ ගැටළුව නම්, එය සැබවින්ම ව්යතිරේකයෙන් උරුම වන සෑම ව්යතිරේකයක්ම ගලවා ගැනීමයි. ඒ .... ඒ සියල්ලම!
රූබි විසින් අභ්යන්තරව භාවිතා කරන සමහර ව්යතිරේක පවතින නිසා එය ගැටළුවක්. ඔවුන්ට ඔබගේ යෙදුම සමඟ කිසිදු සම්බන්ධයක් නැති අතර ඒවා ගිල දැමීමෙන් නරක දේ සිදුවනු ඇත.
මෙන්න ලොකු ඒවා කිහිපයක්:
SignalException :: බාධා කිරීම - ඔබ මෙය ගලවා ගන්නේ නම්, පාලක- c එබීමෙන් ඔබට ඔබගේ යෙදුමෙන් පිටවිය නොහැක.
ScriptError :: SyntaxError - සින්ටැක්ස් දෝෂ ගිල දැමීම යන්නෙන් අදහස් කරන්නේ "(යමක් අමතක වී ඇත) වැනි දේවල් නිහ .ව අසමත් වනු ඇති බවයි.
NoMemoryError - ඔබගේ වැඩසටහන සියලු RAM භාවිතා කිරීමෙන් පසුව දිගටම ක්රියාත්මක වන විට කුමක් සිදුවේදැයි දැන ගැනීමට අවශ්යද? මමත් නැහැ.
begin do_something() rescue Exception => e # Don't do this. This will swallow every single exception. Nothing gets past it. end
මෙම පද්ධති මට්ටමේ ව්යතිරේකයන් කිසිවක් ගිල දැමීමට ඔබට අවශ්ය නැති බව මම අනුමාන කරමි. ඔබට අවශ්ය වන්නේ ඔබගේ යෙදුම් මට්ටමේ සියලු දෝෂයන් පමණි. ව්යතිරේකයන් ඔබගේ කේතයට හේතු විය.
වාසනාවකට මෙන්, මේ සඳහා පහසු ක්රමයක් තිබේ.