# 捕捉されない例外を捕捉する
_published: 2008/06/06_ 
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までの話しだっけ?