method - ruby try error
なぜRubyで `Exception=> e`を救うのが悪いのですか? (4)
本当のルールは:例外を捨てないでください。 あなたの見積もりの著者の客観性は疑わしいです。
または私はあなたを刺すでしょう
もちろん、シグナルは(デフォルトで)例外をスローすることに注意してください。通常、長時間実行されているプロセスはシグナルによって終了します。したがって、Exceptionをキャッチし、シグナル例外で終了しないと、プログラムは非常に停止しにくくなります。 だからこれをしないでください:
#! /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
と言う場合に起こり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
上記はRubyのデフォルトの例外ハンドラの変形であり、あなたのプログラムもkillされないという利点があります。 Railsはリクエストハンドラでこれを行います。
シグナルの例外はメインスレッドで発生します。 バックグラウンドスレッドはそれらを取得しないので、そこにキャッチしようとすることはありません。
これは、プロダクション環境で特に役に立ちます。プロダクション環境では、何か問題が発生したときにプログラムを停止する必要がありません。 次に、ログ内のスタックダンプを取得し、特定の例外をコールチェーンの下に、より優雅に処理するためにコードに追加することができます。
Rubyイディオムには他にも同じ効果があることに注意してください。
a = do_something rescue "something else"
この行では、 do_something
が例外を発生させた場合、Rubyにキャッチされ、投げ捨てられ、 a
は"something else"
が割り当てられ"something else"
。
一般的に、心配する必要がないことを知っている特別な場合を除いて、そうしないでください。 一例:
debugger rescue nil
debugger
関数はあなたのコードにブレークポイントを設定するのに適していますが、デバッガとRailsの外側で実行すると例外が発生します。 今理論的には、デバッグコードをあなたのプログラムの中に置いてはいけません(pff!誰もしません!)何らかの理由でしばらくの間そこに置いておきますが、デバッガを絶えず実行しないでください。
注意:
シグナル例外をキャッチして無視する他の人のプログラムを実行した場合(上記のコードを参照)、次のようになります。
- Linuxでは、シェルで、
pgrep ruby
またはps | grep ruby
ps | grep ruby
、問題のプログラムのPIDを探し、kill -9 <PID>
実行します。 - Windowsでは、タスクマネージャー( CTRL - SHIFT - ESC )を使い、 "プロセス"タブに行き、プロセスを見つけて右クリックして "プロセス終了"を選択します。
- Linuxでは、シェルで、
どんな理由であれ、他の誰かのプログラムと一緒に作業している場合は、これらの無視する例外ブロックがあるので、これをメインラインの一番上に置いてください。
%W/INT QUIT TERM/.each { |sig| trap sig,"SYSTEM_DEFAULT" }
これにより、プログラムは、 クリーンアップなしで 、例外ハンドラをバイパスして直ちに終了することによって、正常終了信号に応答します。 そのため、データの損失などが発生する可能性があります。 注意してください!
これを行う必要がある場合:
begin do_something rescue Exception => e critical_cleanup raise end
実際にこれを行うことができます:
begin do_something ensure critical_cleanup end
2番目のケースでは、例外がスローされたかどうかにかかわらず、毎回
critical cleanup
が呼び出されます。
TL; DR :一般的な例外キャッチの代わりにStandardError
を使用します。 元の例外が再発生した場合(例外をログに記録するために救助する場合など)、 Exception
救済するのはおそらく大丈夫です。
Exception
はRubyの例外階層の根源ですLoadError
をrescue Exception
するときは、 LoadError
、 LoadError
、 Interrupt
などのサブクラスを含むすべてのものから救助してください。
Rescuing Interrupt
は、ユーザーがCTRL Cを使用してプログラムを終了できないようにします。
Rescuing SignalException
は、プログラムがシグナルに正しく応答しないようにします。 それはkill -9
を除いて不十分です。
SyntaxErrorを救うSyntaxError
は、失敗したeval
SyntaxError
ことを意味します。
これらのすべては、このプログラムを実行し、 CTRL Cを押すか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
から救助されException
。 通常、デフォルトのStandardError
よりも具体的なものを指定する必要がありますが、 Exception
からレスキューすることで 、範囲を広げるのではなくスコープが広がり 、致命的な結果をもたらし、バグ狩りを非常に困難にする可能性があります。
StandardError
から救いたい状況があり、例外がある変数が必要な場合は、次の形式を使用できます。
begin
# iceberg!
rescue => e
# lifeboats
end
これは以下と同等です:
begin
# iceberg!
rescue StandardError => e
# lifeboats
end
Exception
からレスキューするのが賢明ないくつかの一般的なケースの1つは、ログ記録/レポートのためのものです。その場合は、すぐに例外を再発生する必要があります。
begin
# iceberg?
rescue Exception => e
# do some logging
raise e # not enough lifeboats ;)
end
これはすべての例外をキャプチャするためです。 あなたのプログラムはそれらのいずれかから回復することはほとんどありません。
復旧方法を知っている例外だけを処理する必要があります。 特定の種類の例外を予期しない場合は、それを処理せず、大声でクラッシュさせ(ログに詳細を書き込む)、ログを診断してコードを修正してください。
例外を飲み込むことは悪いです。これをしないでください。
ルールの特定のケースでは、処理方法がわからない例外をキャッチすべきではありません。 どのように処理するのかわからない場合は、システムの他の部分にキャッチして処理させる方が良いでしょう。