├── .gitignore ├── .travis.yml ├── Appraisals ├── Gemfile ├── LICENSE.md ├── README.md ├── Rakefile ├── exception_notification-rake.gemspec ├── gemfiles ├── activesupport_4.2.gemfile ├── activesupport_5.2.gemfile └── activesupport_6.gemfile ├── lib ├── exception_notification │ └── rake.rb └── exception_notifier │ ├── rake.rb │ └── rake │ ├── rake.rb │ ├── rake_patch.rb │ └── version.rb └── test └── rake_test.rb /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | coverage 6 | Gemfile.lock 7 | gemfiles/*.lock 8 | gemfiles/.bundle 9 | InstalledFiles 10 | lib/bundler/man 11 | pkg 12 | rdoc 13 | spec/reports 14 | test/tmp 15 | test/version_tmp 16 | tmp 17 | 18 | # YARD artifacts 19 | .yardoc 20 | _yardoc 21 | doc/ 22 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 2.0 4 | - 2.1 5 | - 2.2 6 | - 2.3 7 | - 2.4 8 | - 2.5 9 | - 2.6 10 | - 2.7 11 | gemfile: 12 | - gemfiles/activesupport_4.2.gemfile 13 | - gemfiles/activesupport_5.2.gemfile 14 | - gemfiles/activesupport_6.gemfile 15 | jobs: 16 | exclude: 17 | - rvm: 2.0 18 | gemfile: gemfiles/activesupport_5.2.gemfile 19 | - rvm: 2.0 20 | gemfile: gemfiles/activesupport_6.gemfile 21 | - rvm: 2.1 22 | gemfile: gemfiles/activesupport_5.2.gemfile 23 | - rvm: 2.1 24 | gemfile: gemfiles/activesupport_6.gemfile 25 | - rvm: 2.2 26 | gemfile: gemfiles/activesupport_6.gemfile 27 | - rvm: 2.3 28 | gemfile: gemfiles/activesupport_6.gemfile 29 | - rvm: 2.4 30 | gemfile: gemfiles/activesupport_6.gemfile 31 | -------------------------------------------------------------------------------- /Appraisals: -------------------------------------------------------------------------------- 1 | appraise 'activesupport-4.2' do 2 | gem 'activesupport', '~> 4.2.0' 3 | end 4 | 5 | appraise 'activesupport-5.2' do 6 | gem 'activesupport', '~> 5.2.0' 7 | end 8 | 9 | appraise 'activesupport-6' do 10 | gem 'activesupport', '~> 6.0.0' 11 | end 12 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | gemspec 3 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Nik Haldimann 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | exception_notification-rake - ExceptionNotifier for Rake tasks 2 | ============================================================== 3 | 4 | This Ruby gem is an extension of the [exception_notification gem](http://rubygems.org/gems/exception_notification) to support sending mail (or other sorts of notifications) upon failures in Rake tasks. This is useful if you run Rake tasks as batch jobs on a schedule, particularly if you're using the [Heroku Scheduler add-on](http://addons.heroku.com/scheduler). 5 | 6 | [![Build Status](https://travis-ci.org/nikhaldi/exception_notification-rake.png)](https://travis-ci.org/nikhaldi/exception_notification-rake) 7 | 8 | ## Installation 9 | 10 | If you're using Rails 4.2, 5 or 6 (or you're not using Rails at all), use the latest version of the gem: 11 | 12 | gem 'exception_notification-rake', '~> 0.3.1' 13 | 14 | If you're using Rails 4.1.x, use the 0.2.x line of versions: 15 | 16 | gem 'exception_notification-rake', '~> 0.2.2' 17 | 18 | If you're using Rails 4.0.x, use the 0.1.x line of versions: 19 | 20 | gem 'exception_notification-rake', '~> 0.1.3' 21 | 22 | If you're using Rails 3, use the 0.0.x line of versions: 23 | 24 | gem 'exception_notification-rake', '~> 0.0.7' 25 | 26 | 27 | ## Usage 28 | 29 | ### Configuration for Email Notifications 30 | 31 | **Note:** These examples are for the latest version of the gem (using exception_notification 4+ and Rails 4+). For a Rails 3.2 example [see below](#rails-32-configuration-example). 32 | 33 | Exception notification must be set up in your Rails config files. In general, you'll want to do this in environment-specific config files, such as `config/environments/production.rb`. Minimal configuration: 34 | 35 | # config/environments/production.rb 36 | 37 | YourApp::Application.configure do 38 | # Other configuration here, including ActionMailer config ... 39 | 40 | config.middleware.use ExceptionNotification::Rack, 41 | :ignore_if => lambda { |env, exception| !env.nil? }, 42 | :email => { 43 | :sender_address => %{"notifier" }, 44 | :exception_recipients => %w{your.email@example.com} 45 | } 46 | 47 | ExceptionNotifier::Rake.configure 48 | end 49 | 50 | **Note:** This uses `:ignore_if` to suppress all exception notifications not triggered by a background exception (identified by a `nil` environment). If you want to see all notifications (i.e., also those triggered by requests to the Rails server), omit the `:ignore_if` option. 51 | 52 | If you are already using `ExceptionNotifier` anyway, you don't need to configure it again and all you need is: 53 | 54 | # config/environments/production.rb 55 | 56 | YourApp::Application.configure do 57 | # Other configuration here, including ExceptionNotifer and ActionMailer config ... 58 | 59 | ExceptionNotifier::Rake.configure 60 | end 61 | 62 | **Note:** As a prerequisite for sending mail your Rails Action Mailer needs to be configured in the environment where you're using exception notification. See the [Rails guide on Action Mailer](http://guides.rubyonrails.org/action_mailer_basics.html#action-mailer-configuration). 63 | 64 | 65 | ### Other Notifiers 66 | 67 | exception_notificatons supports a bunch of notifiers other than email. See [its documentation](http://smartinez87.github.io/exception_notification/#notifiers) for details. This gem should generally work out of the box with all notifiers. The Rake command line that led to the failure is available at the `:rake_command_line` key in the `data` dictionary. 68 | 69 | 70 | ### Rails 3.2 Configuration Example 71 | 72 | # config/environments/production.rb 73 | 74 | YourApp::Application.configure do 75 | # Other configuration here, including ActionMailer config ... 76 | 77 | config.middleware.use ExceptionNotifier, 78 | :sender_address => %{"notifier" }, 79 | :exception_recipients => %w{your.email@example.com}, 80 | :ignore_if => lambda { true } 81 | 82 | ExceptionNotifier::Rake.configure 83 | end 84 | 85 | For complete documentation on the Rails 3.2 version see the [corresponding branch on GitHub](https://github.com/nikhaldi/exception_notification-rake/tree/rails3.2). 86 | 87 | 88 | ### Email Notification Example 89 | 90 | Email sent upon a failure will include the Rake tasks executed and a stacktrace. This is the result from calling an undefined method `khaaaaan!` in a task called `failing_task` (the data section contains the executed Rake command line in the `:rake_command_line` key): 91 | 92 | Subject: [ERROR] (NoMethodError) "undefined method `khaaaaan!' for main:Object" 93 | From: "notifier" 94 | To: 95 | 96 | A NoMethodError occurred in background at 2014-07-20 21:25:00 UTC : 97 | 98 | undefined method `khaaaaan!' for main:Object 99 | /Users/haldimann/Projects/nikhaldimann.com/lib/tasks/scheduler.rake:33:in `block in ' 100 | 101 | ------------------------------- 102 | Backtrace: 103 | ------------------------------- 104 | 105 | lib/tasks/scheduler.rake:33:in `block in ' 106 | .rvm/gems/ruby-1.9.3-p327/gems/rake-10.3.2/lib/rake/task.rb:240:in `call' 107 | .rvm/gems/ruby-1.9.3-p327/gems/rake-10.3.2/lib/rake/task.rb:240:in `block in execute' 108 | .rvm/gems/ruby-1.9.3-p327/gems/rake-10.3.2/lib/rake/task.rb:235:in `each' 109 | .rvm/gems/ruby-1.9.3-p327/gems/rake-10.3.2/lib/rake/task.rb:235:in `execute' 110 | .rvm/gems/ruby-1.9.3-p327/gems/rake-10.3.2/lib/rake/task.rb:179:in `block in invoke_with_call_chain' 111 | .rvm/rubies/ruby-1.9.3-p327/lib/ruby/1.9.1/monitor.rb:211:in `mon_synchronize' 112 | .rvm/gems/ruby-1.9.3-p327/gems/rake-10.3.2/lib/rake/task.rb:172:in `invoke_with_call_chain' 113 | .rvm/gems/ruby-1.9.3-p327/gems/rake-10.3.2/lib/rake/task.rb:165:in `invoke' 114 | .rvm/gems/ruby-1.9.3-p327/gems/rake-10.3.2/lib/rake/application.rb:150:in `invoke_task' 115 | .rvm/gems/ruby-1.9.3-p327/gems/rake-10.3.2/lib/rake/application.rb:106:in `block (2 levels) in top_level' 116 | .rvm/gems/ruby-1.9.3-p327/gems/rake-10.3.2/lib/rake/application.rb:106:in `each' 117 | .rvm/gems/ruby-1.9.3-p327/gems/rake-10.3.2/lib/rake/application.rb:106:in `block in top_level' 118 | .rvm/gems/ruby-1.9.3-p327/gems/rake-10.3.2/lib/rake/application.rb:115:in `run_with_threads' 119 | .rvm/gems/ruby-1.9.3-p327/gems/rake-10.3.2/lib/rake/application.rb:100:in `top_level' 120 | .rvm/gems/ruby-1.9.3-p327/gems/rake-10.3.2/lib/rake/application.rb:78:in `block in run' 121 | .rvm/gems/ruby-1.9.3-p327/gems/rake-10.3.2/lib/rake/application.rb:176:in `standard_exception_handling' 122 | .rvm/gems/ruby-1.9.3-p327/gems/rake-10.3.2/lib/rake/application.rb:75:in `run' 123 | .rvm/gems/ruby-1.9.3-p327/gems/rake-10.3.2/bin/rake:33:in `' 124 | .rvm/gems/ruby-1.9.3-p327/bin/rake:19:in `load' 125 | .rvm/gems/ruby-1.9.3-p327/bin/rake:19:in `
' 126 | .rvm/gems/ruby-1.9.3-p327/bin/ruby_noexec_wrapper:14:in `eval' 127 | .rvm/gems/ruby-1.9.3-p327/bin/ruby_noexec_wrapper:14:in `
' 128 | 129 | ------------------------------- 130 | Data: 131 | ------------------------------- 132 | 133 | * data: {:rake_command_line=>"rake failing_task"} 134 | 135 | 136 | ### Usage with Heroku Scheduler 137 | 138 | If you're using Heroku, the [Scheduler add-on](http://addons.heroku.com/scheduler) is a very convenient and cheap way to run scheduled batch jobs. In a Rails environment it's easiest to define batch jobs as Rake tasks. However, the only way to find out whether a task run by the scheduler succeeded or failed is generally reading the logs. 139 | 140 | This gem fixes this issue. [Here is a detailed guide](http://blog.nikhaldimann.com/2013/02/19/failure-notifications-for-rake-tasks-on-the-heroku-scheduler/) about configuring it on Heroku. In summary: If you configure exception notification as described above it should work out of the box with the Heroku Scheduler. (Provided you have email delivery set up in your Heroku app - you could try the [SendGrid add-on](https://addons.heroku.com/sendgrid) which comes in a free version that should be good enough for notifications.) 141 | 142 | 143 | ### Customization 144 | 145 | You can pass configuration options to `ExceptionNotifier::Rake.configure`. These will be 146 | passed through to each notifier you configured with `ExceptionNotifier` (see [its documentation](https://github.com/smartinez87/exception_notification) for details on options). The options will be applied only to notifications sent as a result of Rake failures. 147 | 148 | The most likely options you'll want to use are `:email_prefix` and `:exception_recipients`. Example: 149 | 150 | ExceptionNotifier::Rake.configure( 151 | :email => { 152 | :email_prefix => "[Rake Failure] ", 153 | :exception_recipients => %w{user1@example.com user2@example.com}}) 154 | 155 | This will prefix the email subjects of Rake failure notifications with `[Rake Failure]` and will send them to the two given email addresses. Note that if you set the same options when you configure `ExceptionNotifier` mail notifier itself, they will be overridden but for Rake failures only. 156 | 157 | `:ignore_if` and `:ignore_exceptions` are also supported. But note that the `:ignore_if` block will be evaluated for all exceptions, not just the ones triggered by Rake (this is unavoidable because of the design of exception_notification). The first argument to the block passed to `:ignore_if` is the environment - for all Rake failures and other background exceptions this will be `nil`, giving you some way to distinguish them. 158 | 159 | 160 | ## License 161 | 162 | Distributed under an [MIT license](https://github.com/nikhaldi/exception_notification-rake/blob/master/LICENSE.md). 163 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'bundler' 2 | require 'rake/testtask' 3 | 4 | Bundler::GemHelper.install_tasks 5 | 6 | Rake::TestTask.new(:test) do |test| 7 | test.libs << 'lib' << 'test' 8 | test.test_files = FileList['test/*_test.rb'] 9 | test.verbose = true 10 | test.warning = true 11 | end 12 | 13 | task :default => [:test] 14 | -------------------------------------------------------------------------------- /exception_notification-rake.gemspec: -------------------------------------------------------------------------------- 1 | $:.push File.expand_path("../lib", __FILE__) 2 | require 'exception_notifier/rake/version' 3 | 4 | Gem::Specification.new do |s| 5 | s.name = 'exception_notification-rake' 6 | s.version = ExceptionNotifier::Rake::VERSION 7 | s.platform = Gem::Platform::RUBY 8 | s.authors = ['Nik Haldimann'] 9 | s.email = ['nhaldimann@gmail.com'] 10 | s.homepage = 'https://github.com/nikhaldi/exception_notification-rake' 11 | s.summary = 'Sending exception notifications upon Rake task failures' 12 | s.description = 'An extension of the exception_notification gem to support' + 13 | ' sending mail upon failures in Rake tasks' 14 | 15 | s.required_ruby_version = '>= 2.0' 16 | s.add_runtime_dependency 'exception_notification', '~> 4.3' 17 | # NB: Rake before 0.9.0 won't support the exception hook we're using 18 | s.add_runtime_dependency 'rake', '>= 0.9.0' 19 | 20 | s.add_development_dependency 'appraisal', '~> 2.2.0' 21 | 22 | s.files = Dir['LICENSE.md', 'README.md', 'lib/**/*'] 23 | s.test_files = Dir['test/**/*.rb'] 24 | s.require_paths = ['lib'] 25 | end 26 | -------------------------------------------------------------------------------- /gemfiles/activesupport_4.2.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "http://rubygems.org" 4 | 5 | gem "activesupport", "~> 4.2.0" 6 | 7 | gemspec path: "../" 8 | -------------------------------------------------------------------------------- /gemfiles/activesupport_5.2.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "http://rubygems.org" 4 | 5 | gem "activesupport", "~> 5.2.0" 6 | 7 | gemspec path: "../" 8 | -------------------------------------------------------------------------------- /gemfiles/activesupport_6.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "http://rubygems.org" 4 | 5 | gem "activesupport", "~> 6.0.0" 6 | 7 | gemspec path: "../" 8 | -------------------------------------------------------------------------------- /lib/exception_notification/rake.rb: -------------------------------------------------------------------------------- 1 | # This file exists to support gem autoloading by bundler. 2 | require 'exception_notification' 3 | require 'exception_notifier/rake' 4 | -------------------------------------------------------------------------------- /lib/exception_notifier/rake.rb: -------------------------------------------------------------------------------- 1 | require 'exception_notifier/rake/rake' 2 | require 'exception_notifier/rake/rake_patch' 3 | require 'exception_notifier/rake/version' 4 | -------------------------------------------------------------------------------- /lib/exception_notifier/rake/rake.rb: -------------------------------------------------------------------------------- 1 | require 'exception_notifier' 2 | 3 | module ExceptionNotifier 4 | 5 | class Rake 6 | 7 | @notifier_options = {} 8 | @configured = false 9 | 10 | # Whether Rake exception notifications have been configured. 11 | def self.configured? 12 | @configured 13 | end 14 | 15 | # Configure Rake exception notifications. Should be called in a config file, 16 | # usually in config/environments/production.rb for production use. 17 | # An optional hash of options can be given, which will be passed through 18 | # unchanged to the underlying notifiers. 19 | def self.configure(options = {}) 20 | @configured = true 21 | @notifier_options.merge!(options) 22 | 23 | # There is only a single static list registered ignore_ifs. We make 24 | # ignore_ifs passed to just this configuration only effective for 25 | # background exceptions (the enviornment will be nil). That's the 26 | # best we can do, there isn't really a way to identify just our exceptions. 27 | if options[:ignore_if] 28 | ExceptionNotifier.ignore_if do |exception, passed_options| 29 | passed_options[:env].nil? && options[:ignore_if].call({}, exception) 30 | end 31 | end 32 | end 33 | 34 | def self.notifier_options 35 | @notifier_options 36 | end 37 | 38 | # Deliver a notification about the given exception by email, in case 39 | # notifications have been configured. The additional data hash will 40 | # be passed through to ExceptionNotifier's data hash and will be availble 41 | # in templates. 42 | def self.maybe_deliver_notification(exception, data={}) 43 | if configured? 44 | options = notifier_options 45 | if !data.empty? 46 | options = options.dup 47 | options[:data] = data.merge(options[:data] || {}) 48 | end 49 | ExceptionNotifier.notify_exception(exception, options) 50 | end 51 | end 52 | 53 | def self.reset_for_test 54 | @notifier_options = {} 55 | @configured = false 56 | ExceptionNotifier.clear_ignore_conditions! 57 | end 58 | end 59 | end 60 | -------------------------------------------------------------------------------- /lib/exception_notifier/rake/rake_patch.rb: -------------------------------------------------------------------------------- 1 | # Monkey patching patterns lifted from 2 | # https://github.com/thoughtbot/airbrake/blob/master/lib/airbrake/rake_handler.rb 3 | module ExceptionNotifier 4 | module RakePatch 5 | def display_error_message(ex) 6 | super(ex) 7 | ExceptionNotifier::Rake.maybe_deliver_notification(ex, 8 | :rake_command_line => reconstruct_command_line) 9 | end 10 | 11 | def reconstruct_command_line 12 | "rake #{ARGV.join(' ')}" 13 | end 14 | end 15 | end 16 | 17 | # Only do this if we're actually in a Rake context. In some contexts (e.g., 18 | # in the Rails console) Rake might not be defined. 19 | if Object.const_defined?(:Rake) && Rake.respond_to?(:application) 20 | Rake.application.instance_eval do 21 | class << self 22 | prepend ExceptionNotifier::RakePatch 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /lib/exception_notifier/rake/version.rb: -------------------------------------------------------------------------------- 1 | module ExceptionNotifier 2 | class Rake 3 | VERSION = '0.3.1' 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /test/rake_test.rb: -------------------------------------------------------------------------------- 1 | require "minitest/autorun" 2 | 3 | require 'exception_notifier/rake' 4 | 5 | class RakeTest < Minitest::Test 6 | 7 | class Notifier 8 | attr_accessor :exception, :options 9 | def call(exception, options) 10 | @exception = exception 11 | @options = options 12 | end 13 | end 14 | 15 | class IgnoredException < Exception 16 | end 17 | 18 | def setup 19 | ExceptionNotifier::Rake.reset_for_test 20 | assert !ExceptionNotifier::Rake.configured? 21 | @notifier = Notifier.new 22 | ExceptionNotifier.add_notifier 'test_notifier', @notifier 23 | end 24 | 25 | def assert_not_notified 26 | assert_nil @notifier.exception 27 | assert_nil @notifier.options 28 | end 29 | 30 | def assert_notified(exception, options) 31 | assert_equal exception, @notifier.exception 32 | assert_equal options, @notifier.options 33 | end 34 | 35 | def test_configure_only_default_options 36 | ExceptionNotifier::Rake.configure 37 | assert ExceptionNotifier::Rake.configured? 38 | assert_equal({}, ExceptionNotifier::Rake.notifier_options) 39 | end 40 | 41 | def test_configure_custom_options 42 | some_options = { 43 | :sender_address => 'foo@example.com', 44 | :exception_recipients => ['bar@example.com'], 45 | } 46 | ExceptionNotifier::Rake.configure some_options 47 | assert ExceptionNotifier::Rake.configured? 48 | assert_equal some_options, ExceptionNotifier::Rake.notifier_options 49 | end 50 | 51 | def test_maybe_deliver_notifications_without_configuration 52 | ExceptionNotifier::Rake.maybe_deliver_notification(Exception.new) 53 | assert_not_notified 54 | end 55 | 56 | def test_maybe_deliver_notifications_with_config 57 | ExceptionNotifier::Rake.configure 58 | ex = Exception.new 59 | ExceptionNotifier::Rake.maybe_deliver_notification(ex) 60 | assert_notified ex, ExceptionNotifier::Rake.notifier_options 61 | end 62 | 63 | def test_maybe_deliver_notifications_with_data 64 | ExceptionNotifier::Rake.configure 65 | data = {:foo => :bar} 66 | options = ExceptionNotifier::Rake.notifier_options 67 | original_options = options.dup 68 | ex = Exception.new 69 | ExceptionNotifier::Rake.maybe_deliver_notification(ex, data) 70 | assert_notified ex, options.merge({:data => data}) 71 | assert_equal original_options, options 72 | end 73 | 74 | def test_maybe_deliver_notifications_with_ignore_if 75 | ExceptionNotifier::Rake.configure( 76 | ignore_if: lambda { |env, exception| true }) 77 | ExceptionNotifier::Rake.maybe_deliver_notification(Exception.new) 78 | assert_not_notified 79 | end 80 | 81 | def test_maybe_deliver_notifications_with_passing_ignore_if 82 | ExceptionNotifier::Rake.configure( 83 | ignore_if: lambda { |env, exception| false }) 84 | ex = Exception.new 85 | ExceptionNotifier::Rake.maybe_deliver_notification(ex) 86 | assert_notified ex, ExceptionNotifier::Rake.notifier_options 87 | end 88 | 89 | def test_maybe_deliver_notifications_with_ignore_exceptions 90 | ExceptionNotifier::Rake.configure( 91 | ignore_exceptions: ['RakeTest::IgnoredException']) 92 | ExceptionNotifier::Rake.maybe_deliver_notification(IgnoredException.new) 93 | assert_not_notified 94 | 95 | ex = Exception.new 96 | ExceptionNotifier::Rake.maybe_deliver_notification(ex) 97 | assert_notified ex, ExceptionNotifier::Rake.notifier_options 98 | end 99 | end 100 | --------------------------------------------------------------------------------