diff --git a/config/initializers/honeybadger.rb b/config/initializers/honeybadger.rb new file mode 100644 index 000000000..d6401e7a9 --- /dev/null +++ b/config/initializers/honeybadger.rb @@ -0,0 +1,23 @@ +# Suppress benign shutdown noise. When a pod is terminated (deploy, restart, +# scale-down) the DB connection pool closes while SolidQueue's supervisor is +# still trying to deregister its Process record, so that final query fails with +# a closed connection. There's no request, no user, and nothing is lost — it's +# just restart noise, so we drop it rather than page on it. +# +# Kept narrow on purpose: only closed-connection errors with no component (i.e. +# outside any web request or job) are dropped, so a genuine mid-request DB +# outage still reports. +Honeybadger.configure do |config| + shutdown_error_classes = %w[ + ActiveRecord::ConnectionNotEstablished + Trilogy::EOFError + ] + + config.before_notify do |notice| + connection_error = shutdown_error_classes.include?(notice.error_class) + closed_connection = notice.error_message.to_s.include?("TRILOGY_CLOSED_CONNECTION") + outside_request = notice.component.blank? + + notice.halt! if connection_error && closed_connection && outside_request + end +end diff --git a/spec/initializers/honeybadger_shutdown_filter_spec.rb b/spec/initializers/honeybadger_shutdown_filter_spec.rb new file mode 100644 index 000000000..f136d5f98 --- /dev/null +++ b/spec/initializers/honeybadger_shutdown_filter_spec.rb @@ -0,0 +1,48 @@ +require "rails_helper" + +# Exercises the before_notify hook registered in config/initializers/honeybadger.rb, +# which drops the benign closed-connection error a SolidQueue pod raises while +# deregistering itself during shutdown, without hiding real DB outages. +RSpec.describe "Honeybadger shutdown filter" do + def run_hooks(error_class:, error_message:, component:) + notice = instance_double( + Honeybadger::Notice, + error_class: error_class, + error_message: error_message, + component: component + ) + allow(notice).to receive(:halt!) + Honeybadger.config.before_notify_hooks.each { |hook| hook.call(notice) } + notice + end + + it "drops a closed-connection error raised outside any request (pod shutdown noise)" do + notice = run_hooks( + error_class: "ActiveRecord::ConnectionNotEstablished", + error_message: "trilogy_connect - unable to connect to db:25060: TRILOGY_CLOSED_CONNECTION", + component: nil + ) + + expect(notice).to have_received(:halt!) + end + + it "keeps a closed-connection error raised during a request" do + notice = run_hooks( + error_class: "ActiveRecord::ConnectionNotEstablished", + error_message: "trilogy_connect - ...: TRILOGY_CLOSED_CONNECTION", + component: "GrantsController" + ) + + expect(notice).not_to have_received(:halt!) + end + + it "keeps a genuine can't-reach-the-database error" do + notice = run_hooks( + error_class: "ActiveRecord::ConnectionNotEstablished", + error_message: "trilogy_connect - unable to connect: Connection refused", + component: nil + ) + + expect(notice).not_to have_received(:halt!) + end +end