From 0577a530f7aa86c8ccc03431218792231a210823 Mon Sep 17 00:00:00 2001 From: Justin Howard Date: Thu, 2 Sep 2021 11:43:51 -0700 Subject: [PATCH] Suppress circuit_success for proxy circuits --- lib/faulty/cache/circuit_proxy.rb | 2 +- lib/faulty/events.rb | 1 + lib/faulty/events/filter_notifier.rb | 31 +++++++++++++++++++++++++++ lib/faulty/storage/circuit_proxy.rb | 2 +- spec/cache/circuit_proxy_spec.rb | 7 ++++++ spec/events/filter_notifier_spec.rb | 32 ++++++++++++++++++++++++++++ spec/storage/circuit_proxy_spec.rb | 7 ++++++ 7 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 lib/faulty/events/filter_notifier.rb create mode 100644 spec/events/filter_notifier_spec.rb diff --git a/lib/faulty/cache/circuit_proxy.rb b/lib/faulty/cache/circuit_proxy.rb index f28f3d5..51c1e70 100644 --- a/lib/faulty/cache/circuit_proxy.rb +++ b/lib/faulty/cache/circuit_proxy.rb @@ -33,7 +33,7 @@ def finalize self.circuit ||= Circuit.new( Faulty::Storage::CircuitProxy.name, - notifier: notifier, + notifier: Events::FilterNotifier.new(notifier, exclude: %i[circuit_success]), cache: Cache::Null.new ) end diff --git a/lib/faulty/events.rb b/lib/faulty/events.rb index ebdd58f..1044888 100644 --- a/lib/faulty/events.rb +++ b/lib/faulty/events.rb @@ -26,3 +26,4 @@ module Events require 'faulty/events/honeybadger_listener' require 'faulty/events/log_listener' require 'faulty/events/notifier' +require 'faulty/events/filter_notifier' diff --git a/lib/faulty/events/filter_notifier.rb b/lib/faulty/events/filter_notifier.rb new file mode 100644 index 0000000..8b2b521 --- /dev/null +++ b/lib/faulty/events/filter_notifier.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +class Faulty + module Events + # Wraps a Notifier and filters events by name + class FilterNotifier + # @param notifier [Notifier] The internal notifier to filter events for + # @param events [Array, nil] An array of events to allow. If nil, all + # {EVENTS} will be used + # @param exclude [Array, nil] An array of events to disallow. If nil, + # no events will be disallowed. Takes priority over `events`. + def initialize(notifier, events: nil, exclude: nil) + @notifier = notifier + @events = Set.new(events || EVENTS) + exclude&.each { |e| @events.delete(e) } + end + + # Notify all listeners of an event + # + # If a listener raises an error while handling an event, that error will + # be captured and written to STDERR. + # + # @param (see Notifier) + def notify(event, payload) + return unless @events.include?(event) + + @notifier.notify(event, payload) + end + end + end +end diff --git a/lib/faulty/storage/circuit_proxy.rb b/lib/faulty/storage/circuit_proxy.rb index e00518b..c89fe5b 100644 --- a/lib/faulty/storage/circuit_proxy.rb +++ b/lib/faulty/storage/circuit_proxy.rb @@ -33,7 +33,7 @@ def finalize self.circuit ||= Circuit.new( Faulty::Storage::CircuitProxy.name, - notifier: notifier, + notifier: Events::FilterNotifier.new(notifier, exclude: %i[circuit_success]), cache: Cache::Null.new ) end diff --git a/spec/cache/circuit_proxy_spec.rb b/spec/cache/circuit_proxy_spec.rb index bc03207..13e0c4d 100644 --- a/spec/cache/circuit_proxy_spec.rb +++ b/spec/cache/circuit_proxy_spec.rb @@ -28,6 +28,13 @@ def respond_to_missing?(*_args) expect { proxy.read('foo') }.to raise_error(Faulty::CircuitTrippedError) end + it 'does not notify for circuit sucesses by default' do + expect(notifier).not_to receive(:notify) + backend = Faulty::Cache::Mock.new + proxy = described_class.new(backend, notifier: notifier) + proxy.read('foo') + end + it 'delegates fault_tolerant? directly' do backend = instance_double(Faulty::Cache::Mock) marker = Object.new diff --git a/spec/events/filter_notifier_spec.rb b/spec/events/filter_notifier_spec.rb new file mode 100644 index 0000000..a90fed0 --- /dev/null +++ b/spec/events/filter_notifier_spec.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +RSpec.describe Faulty::Events::FilterNotifier do + let(:backend) { Faulty::Events::Notifier.new } + + it 'forwards all events by default' do + filter = described_class.new(backend) + expect(backend).to receive(:notify).with(:circuit_success, {}) + filter.notify(:circuit_success, {}) + end + + it 'forwards only given events' do + filter = described_class.new(backend, events: %i[circuit_failure]) + expect(backend).to receive(:notify).with(:circuit_failure, {}) + filter.notify(:circuit_success, {}) + filter.notify(:circuit_failure, {}) + end + + it 'forwards all except exluded events' do + filter = described_class.new(backend, exclude: %i[circuit_success]) + expect(backend).to receive(:notify).with(:circuit_failure, {}) + filter.notify(:circuit_success, {}) + filter.notify(:circuit_failure, {}) + end + + it 'forwards given events except excluded' do + filter = described_class.new(backend, events: %i[circuit_failure circuit_success], exclude: %i[circuit_success]) + expect(backend).to receive(:notify).with(:circuit_failure, {}) + filter.notify(:circuit_success, {}) + filter.notify(:circuit_failure, {}) + end +end diff --git a/spec/storage/circuit_proxy_spec.rb b/spec/storage/circuit_proxy_spec.rb index 61c4b2d..f9e913b 100644 --- a/spec/storage/circuit_proxy_spec.rb +++ b/spec/storage/circuit_proxy_spec.rb @@ -30,4 +30,11 @@ def respond_to_missing?(*_args) expect { proxy.entry(circuit, Faulty.current_time, true) } .to raise_error(Faulty::CircuitTrippedError) end + + it 'does not notify for circuit sucesses by default' do + expect(notifier).not_to receive(:notify) + backend = Faulty::Storage::Null.new + proxy = described_class.new(backend, notifier: notifier) + proxy.entry(circuit, Faulty.current_time, true) + end end