# 捕捉されない例外を捕捉する _published: 2008/06/06_ ![alt](http://b.hatena.ne.jp/entry/image/http://d.hatena.ne.jp/shunsuk/20080606/1212754833) RailsでActionMailerを使っていて、SMTP over TLSでメールを送信する場合。tlsmailを使います。 - [Rubyでメールを送信するための基礎知識 - このブログは証明できない。](http://d.hatena.ne.jp/shunsuk/20080402/1207143302) そして、こんなカンジでメール送信。 ```ruby TestMailer.deliver_send_mail ``` ごくマレに、タイムアウト発生。 そこで、例外を捕捉。 ```ruby begin TestMailer.deliver_send_mail rescue render :text => '送信エラーです。' end ``` あれ?捕まえられない? tlsmailのソースを見る。 `/user/lib/ruby/gems/1.8/gems/tlsmail-0.0.1/lib/net/smtp.rb` ```ruby def do_start(helodomain, user, secret, authtype) # 省略 s = timeout(@open_timeout) { TCPSocket.open(@address, @port) } # 省略 end ``` `timeout` を使ってる。 `timeout` のソースを見る。 `/usr/lib/ruby/1.8/timeout.rb` ```ruby def timeout(sec, exception=Error) return yield if sec == nil or sec.zero? raise ThreadError, "timeout within critical session" if Thread.critical begin x = Thread.current y = Thread.start { sleep sec x.raise exception, "execution expired" if x.alive? } yield sec # return true ensure y.kill if y and y.alive? end end ``` Rubyのマルチスレッドのコードは初めて見ました。currentスレッドの `raise` メソッドで例外を発生させてますね。で、発生する例外は `Timeout::Error` 。 `rescue` は、捕捉する例外クラスを指定しない場合、 `StandardError` を捕捉します。そして、 `Timeout::Error` は `StandardError` のサブクラスではないので、捕捉されない。 そこで、 `rescue` に `Timeout::Error` を指定。それだけでは `StandardError` が捕捉されなくなるので、 `StandardError` も指定。 ```ruby begin TestMailer.deliver_send_mail rescue Timeout::Error, StandardError render :text => '送信エラーです。' end ``` 捕まえた! 参考: - [no title](http://shunirr.org/archives/115) - [RubyでTimeout::Errorを無視したい。](http://q.hatena.ne.jp/1180850904) .NETも捕捉されない例外があります。アプリケーション全体をtry-catchしても、ダメです。 ```cs try { // アプリ全体 } catch { // すべての例外を捕捉するはずなのに。。 } ``` マルチスレッドやってると、 `ThreadAbortException` が発生することがあります。これが上のコードでは捕捉できません。 そこで、Windowsフォームなら、 `Application.ThreadException` 。それ以外なら、 `AppDomain.UnhandledException` のイベントハンドラで例外処理をすればOKです。 こんなカンジ。 ```cs Application.ThreadException += delegate(object sender, ThreadExceptionEventArgs t) { // エラー処理 }; ``` でも、.NET2.0までの話しだっけ?