delayed_jobs は極めて簡単に非同期処理を実現してくれる素敵gem。
see:
Railsで非同期処理が簡単に実装できる「Delayed_job」が便利すぎる
[ruby] delayed_job ちょっとだけ詳しく
exception_notification は Railsでの例外発生時に詳細を記述したエラー通知メールを送信してくれる素敵gem。
see:
[Rails本番運用で役に立つプラグイン exception_notification](http://d.hatena.ne.jp/the_yokochi/ 20110517/1305641153)
Rails3 で exception_notification プラグインを使う
exception_notification なしでは安心して眠れないくらいに頼りになるのですが、実は delayed_jobs の遅延処理タスクとして動作しているときは通知処理を行なってくれないという問題が。
これでは眠れなくなってしまうので、次のような記述を追加します。
# exception_notifier にメソッドが存在することを確認。
[[ExceptionNotifier::Notifier, :background_exception_notification]].each do |object, method_name|
raise NoMethodError, "undefined method `#{method_name}' for #{object.inspect}" unless object.respond_to?(method_name, true)
end
# workrが失敗を検出した時のハンドラ(Delayed::Worker#handle_failed_job)にメール送信処理を追加
Delayed::Worker.class_eval do
def handle_failed_job_with_notification(job, error)
handle_failed_job_without_notification(job, error)
begin
ExceptionNotifier::Notifier.background_exception_notification(error)
rescue Exception => e
# メール送信失敗時はログに記録
Rails.logger.error "ExceptionNotifier failed: #{e.class.name}: #{e.message}"
e.backtrace.each do |f|
Rails.logger.error " #{f}"
end
Rails.logger.flush
end
end
alias_method_chain :handle_failed_job, :notification
end
これで非同期処理中のエラーも検出できるようになりました。
ただし、失敗時にはわりと短い時間で再試行するの、再現性のあるエラーの場合は同じようなメールが複数届いてしまってちょっと嫌な感じですが、あんまり気にしません。
以下の Q&A を参考にしました:
How to make ExceptionNotifier work with delayed_job in Rails 3?
追記
delayed_jobs 4.0 から ExceptionNotifier::Notifier.background_exception_notification(error)
に代わって、ExceptionNotifier.notify_exception(error)
を使うようになったので下記のようになります。
# exception_notifier にメソッドが存在することを確認。
[[ExceptionNotifier, :notify_exception]].each do |object, method_name|
raise NoMethodError, "undefined method `#{method_name}' for #{object.inspect}" unless object.respond_to?(method_name, true)
end
# workrが失敗を検出した時のハンドラ(Delayed::Worker#handle_failed_job)にメール送信処理を追加
Delayed::Worker.class_eval do
def handle_failed_job_with_notification(job, error)
handle_failed_job_without_notification(job, error)
begin
ExceptionNotifier.notify_exception(error)
rescue Exception => e
# メール送信失敗時はログに記録
Rails.logger.error "ExceptionNotifier failed: #{e.class.name}: #{e.message}"
e.backtrace.each do |f|
Rails.logger.error " #{f}"
end
Rails.logger.flush
end
end
alias_method_chain :handle_failed_job, :notification
end