diff --git a/activesupport/lib/active_support/notifications/fanout.rb b/activesupport/lib/active_support/notifications/fanout.rb index 2bc782ecee2cc..af70faf407293 100644 --- a/activesupport/lib/active_support/notifications/fanout.rb +++ b/activesupport/lib/active_support/notifications/fanout.rb @@ -17,26 +17,30 @@ def initialize(exceptions) end module FanoutIteration # :nodoc: - def iterate_guarding_exceptions(listeners) - exceptions = nil - - listeners.each do |s| - yield s - rescue Exception => e - exceptions ||= [] - exceptions << e - end + private + def iterate_guarding_exceptions(collection) + exceptions = nil - if exceptions - if exceptions.size == 1 - raise exceptions.first - else - raise InstrumentationSubscriberError.new(exceptions), cause: exceptions.first + collection.each do |s| + yield s + rescue Exception => e + exceptions ||= [] + exceptions << e end - end - listeners - end + if exceptions + exceptions = exceptions.flat_map do |exception| + exception.is_a?(InstrumentationSubscriberError) ? exception.exceptions : [exception] + end + if exceptions.size == 1 + raise exceptions.first + else + raise InstrumentationSubscriberError.new(exceptions), cause: exceptions.first + end + end + + collection + end end # This is a default queue implementation that ships with Notifications. @@ -222,6 +226,8 @@ def groups_for(name) # :nodoc: # handle.finish # end class Handle + include FanoutIteration + def initialize(notifier, name, id, payload) # :nodoc: @name = name @id = id @@ -236,7 +242,7 @@ def start ensure_state! :initialized @state = :started - @groups.each do |group| + iterate_guarding_exceptions(@groups) do |group| group.start(@name, @id, @payload) end end @@ -249,7 +255,7 @@ def finish_with_values(name, id, payload) # :nodoc: ensure_state! :started @state = :finished - @groups.each do |group| + iterate_guarding_exceptions(@groups) do |group| group.finish(name, id, payload) end end diff --git a/activesupport/test/notifications/evented_notification_test.rb b/activesupport/test/notifications/evented_notification_test.rb index 2933b46d25bb1..fa96faff20fbd 100644 --- a/activesupport/test/notifications/evented_notification_test.rb +++ b/activesupport/test/notifications/evented_notification_test.rb @@ -126,6 +126,9 @@ def test_listen_finish_multiple_exception_consistency listener = Listener.new notifier.subscribe nil, BadFinishListener.new notifier.subscribe nil, BadFinishListener.new + notifier.subscribe(nil) { |*args| raise "foo" } + notifier.subscribe(nil) { |obj| raise "foo" } + notifier.subscribe(nil, monotonic: true) { |obj| raise "foo" } notifier.subscribe nil, listener notifier.start "hello", 1, {} @@ -133,11 +136,13 @@ def test_listen_finish_multiple_exception_consistency error = assert_raises InstrumentationSubscriberError do notifier.finish "world", 1, {} end + assert_equal 5, error.exceptions.count assert_instance_of BadListenerException, error.cause error = assert_raises InstrumentationSubscriberError do notifier.finish "hello", 1, {} end + assert_equal 5, error.exceptions.count assert_instance_of BadListenerException, error.cause assert_equal 4, listener.events.length