diff --git a/sentry-ruby/lib/sentry-ruby.rb b/sentry-ruby/lib/sentry-ruby.rb index b7ecdea53..b426d61ec 100644 --- a/sentry-ruby/lib/sentry-ruby.rb +++ b/sentry-ruby/lib/sentry-ruby.rb @@ -308,6 +308,9 @@ def csp_report_uri # @return [Hub] def get_main_hub MUTEX.synchronize { @main_hub } + rescue ThreadError + # In some rare cases this may be called in a trap context so we need to handle it gracefully + @main_hub end # Takes an instance of Sentry::Breadcrumb and stores it to the current active scope. diff --git a/sentry-ruby/spec/sentry_spec.rb b/sentry-ruby/spec/sentry_spec.rb index 9a188e9f3..fda75c272 100644 --- a/sentry-ruby/spec/sentry_spec.rb +++ b/sentry-ruby/spec/sentry_spec.rb @@ -70,6 +70,44 @@ end end end + + context "works within a trap context" do + it "reproduces mutex issue in trap handler" do + read_pipe, write_pipe = IO.pipe + + pid = fork do + read_pipe.close + + described_class.init do |config| + config.dsn = Sentry::TestHelper::DUMMY_DSN + end + + trap('HUP') do + hub = described_class.get_main_hub + write_pipe.write(hub.class.to_s) + write_pipe.close + end + + Process.kill('HUP', Process.pid) + end + + write_pipe.close + + start_time = Time.now + timeout = 1.0 + result = nil + + while Time.now - start_time < timeout + break if Process.wait(pid, Process::WNOHANG) + sleep 0.01 + end + + result = read_pipe.read unless read_pipe.closed? + read_pipe.close + + expect(result).to eq("Sentry::Hub") + end + end end describe "#clone_hub_to_current_thread" do