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

いいえ、本当にそれをしないでください。 それが動作するかどうかを確認するためにそれを実行しないでください。

しかし、スレッド化されたサーバーがあり、すべての例外をそうしないとします。

  1. 無視される(デフォルト)
  2. サーバーを停止します(これは、 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!誰もしません!)何らかの理由でしばらくの間そこに置いておきますが、デバッガを絶えず実行しないでください。

注意:

  1. シグナル例外をキャッチして無視する他の人のプログラムを実行した場合(上記のコードを参照)、次のようになります。

    • Linuxでは、シェルで、 pgrep rubyまたはps | grep ruby ps | grep ruby 、問題のプログラムのPIDを探し、 kill -9 <PID>実行します。
    • Windowsでは、タスクマネージャー( CTRL - SHIFT - ESC )を使い、 "プロセス"タブに行き、プロセスを見つけて右クリックして "プロセス終了"を選択します。
  2. どんな理由であれ、他の誰かのプログラムと一緒に作業している場合は、これらの無視する例外ブロックがあるので、これをメインラインの一番上に置いてください。

    %W/INT QUIT TERM/.each { |sig| trap sig,"SYSTEM_DEFAULT" }
    

    これにより、プログラムは、 クリーンアップなしで 、例外ハンドラをバイパスして直ちに終了することによって、正常終了信号に応答します。 そのため、データの損失などが発生する可能性があります。 注意してください!

  3. これを行う必要がある場合:

    begin
      do_something
    rescue Exception => e
      critical_cleanup
      raise
    end
    

    実際にこれを行うことができます:

    begin
      do_something
    ensure
      critical_cleanup
    end
    

    2番目のケースでは、例外がスローされたかどうかにかかわらず、毎回critical cleanupが呼び出されます。

Ryan DavisのRuby QuickRefによると(説明なし):

例外を救助しないでください。 これまで または私はあなたを刺すでしょう。

何故なの? 何が正しいのですか?


TL; DR :一般的な例外キャッチの代わりにStandardErrorを使用します。 元の例外が再発生した場合(例外をログに記録するために救助する場合など)、 Exception救済するのはおそらく大丈夫です。

ExceptionRubyの例外階層の根源ですLoadErrorrescue Exceptionするときは、 LoadErrorLoadErrorInterruptなどのサブクラスを含むすべてのものから救助しください。

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

これはすべての例外をキャプチャするためです。 あなたのプログラムはそれらのいずれかから回復することはほとんどありません。

復旧方法を知っている例外だけを処理する必要があります。 特定の種類の例外を予期しない場合は、それを処理せず、大声でクラッシュさせ(ログに詳細を書き込む)、ログを診断してコードを修正してください。

例外を飲み込むことは悪いです。これをしないでください。


ルールの特定のケースでは、処理方法がわからない例外をキャッチすべきではありません。 どのように処理するのかわからない場合は、システムの他の部分にキャッチして処理させる方が良いでしょう。





exception-handling