Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions yes-core/lib/yes/core/failed_subscription_notifier.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# frozen_string_literal: true

module Yes
module Core
# Reports a permanently dead pg_eventstore subscription to Sentry.
#
# pg_eventstore calls its +failed_subscription_notifier+ exactly once, when a
# subscription exhausts its restarts and stays dead — it is the gem's only
# death signal, and without it that death is silent (B2BY-5189). Per-failure
# errors are only recorded on the subscription row, never raised into Sentry.
class FailedSubscriptionNotifier
# @param subscription [PgEventstore::Subscription]
# @param error [StandardError]
# @return [void]
def call(subscription, error)
Sentry.with_scope do |scope|
scope.set_tags(failed_subscription_notifier: true) # used in Sentry Alerts

Sentry.capture_exception(
error,
# a death report must never be swallowed by Sentry's excluded_exceptions
hint: { ignore_exclusions: true },
extra: { id: subscription.id, set: subscription.set, name: subscription.name }
)
end
end
end
end
end
5 changes: 5 additions & 0 deletions yes-core/lib/yes/core/railtie.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ class Railtie < Rails::Railtie
with_indifferent_access: Yes::Core::Middlewares::WithIndifferentAccess.new,
timestamp: Yes::Core::Middlewares::Timestamp.new
}

# pg_eventstore's only death signal — without it a subscription that
# exhausts its restarts dies silently (B2BY-5189). Present in
# yousty-eventsourcing's Railtie; dropped when it was ported here.
config.failed_subscription_notifier = FailedSubscriptionNotifier.new if defined?(Sentry)
end
end

Expand Down
31 changes: 31 additions & 0 deletions yes-core/spec/lib/yes/core/failed_subscription_notifier_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# frozen_string_literal: true

RSpec.describe Yes::Core::FailedSubscriptionNotifier do
subject(:notify) { described_class.new.call(subscription, error) }

let(:subscription) { PgEventstore::Subscription.new(id: 42, set: 'Yes', name: 'SomeProcessManager') }
let(:error) { StandardError.new('handler exploded') }
let(:sentry) { class_double('Sentry') }
let(:scope) { double('Sentry::Scope', set_tags: nil) }

before do
# Sentry is not a dependency of this gem — the railtie only registers the
# notifier when the host app loaded it, so the constant is stubbed here.
stub_const('Sentry', sentry)
allow(sentry).to receive(:with_scope).and_yield(scope)
allow(sentry).to receive(:capture_exception)
end

it 'reports the death to Sentry with the subscription identity' do
notify

aggregate_failures do
expect(scope).to have_received(:set_tags).with(failed_subscription_notifier: true)
expect(sentry).to have_received(:capture_exception).with(
error,
hint: { ignore_exclusions: true },
extra: { id: 42, set: 'Yes', name: 'SomeProcessManager' }
)
end
end
end
Loading