diff --git a/CHANGELOG.md b/CHANGELOG.md index d651459f4..a289dde3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,15 @@ Changelog ========= +## TBD + +### Fixes + +* Handle `nil` values for the `job` block parameter for the Que error notifier. + This occurs under some conditions such as database connection failures. + | [#545](https://github.com/bugsnag/bugsnag-ruby/issues/545) + | [#548](https://github.com/bugsnag/bugsnag-ruby/pull/548) + ## 6.11.1 (22 Jan 2019) ### Fixes diff --git a/lib/bugsnag/integrations/que.rb b/lib/bugsnag/integrations/que.rb index ff088570a..fee75adf4 100644 --- a/lib/bugsnag/integrations/que.rb +++ b/lib/bugsnag/integrations/que.rb @@ -1,21 +1,23 @@ if defined?(::Que) handler = proc do |error, job| begin - job = job.dup # Make sure the original job object is not mutated. + job &&= job.dup # Make sure the original job object is not mutated. Bugsnag.notify(error, true) do |report| - job[:error_count] += 1 + if job + job[:error_count] += 1 - # If the job was scheduled using ActiveJob then unwrap the job details for clarity: - if job[:job_class] == "ActiveJob::QueueAdapters::QueAdapter::JobWrapper" - wrapped_job = job[:args].last - wrapped_job = wrapped_job.each_with_object({}) { |(k, v), result| result[k.to_sym] = v } # Symbolize keys + # If the job was scheduled using ActiveJob then unwrap the job details for clarity: + if job[:job_class] == "ActiveJob::QueueAdapters::QueAdapter::JobWrapper" + wrapped_job = job[:args].last + wrapped_job = wrapped_job.each_with_object({}) { |(k, v), result| result[k.to_sym] = v } # Symbolize keys - # Align key names with keys in `job` - wrapped_job[:queue] = wrapped_job.delete(:queue_name) - wrapped_job[:args] = wrapped_job.delete(:arguments) + # Align key names with keys in `job` + wrapped_job[:queue] = wrapped_job.delete(:queue_name) + wrapped_job[:args] = wrapped_job.delete(:arguments) - job.merge!(wrapper_job_class: job[:job_class], wrapper_job_id: job[:job_id]).merge!(wrapped_job) + job.merge!(wrapper_job_class: job[:job_class], wrapper_job_id: job[:job_id]).merge!(wrapped_job) + end end report.add_tab(:job, job) @@ -41,4 +43,4 @@ Bugsnag.configuration.app_type ||= "que" Que.error_handler = handler end -end \ No newline at end of file +end diff --git a/spec/integrations/que_spec.rb b/spec/integrations/que_spec.rb index 259217eb6..c1c212a07 100644 --- a/spec/integrations/que_spec.rb +++ b/spec/integrations/que_spec.rb @@ -6,6 +6,9 @@ unless defined?(::Que) @mocked_que = true class ::Que + class << self + attr_accessor :error_notifier + end end end end @@ -25,7 +28,6 @@ class ::Que expect(report).to receive(:add_tab).with(:job, { :error_count => 1, :job_class => 'ActiveJob::QueueAdapters::QueAdapter::JobWrapper', - :args => [{"queue_name" => "foo", "arguments" => "bar"}], :job_id => "ID", :wrapper_job_class => 'ActiveJob::QueueAdapters::QueAdapter::JobWrapper', :wrapper_job_id => "ID", @@ -54,6 +56,24 @@ class ::Que load './lib/bugsnag/integrations/que.rb' end + context 'when the job is nil' do + it 'notifies Bugsnag' do + load './lib/bugsnag/integrations/que.rb' + error = RuntimeError.new('nil job') + report = Bugsnag::Report.new(error, Bugsnag::Configuration.new) + expect(Bugsnag).to receive(:notify).with(error, true).and_yield(report) + + Que.error_notifier.call(error, nil) + + expect(report.meta_data['custom'].fetch('job')).to eq(nil) + expect(report.severity).to eq('error') + expect(report.severity_reason).to eq({ + :type => Bugsnag::Report::UNHANDLED_EXCEPTION_MIDDLEWARE, + :attributes => {:framework => 'Que'}, + }) + end + end + after do Object.send(:remove_const, :Que) if @mocked_que end