Skip to content
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- Improve the accuracy of duration calculations in cron jobs monitoring ([#2471](https://github.com/getsentry/sentry-ruby/pull/2471))
- Use attempt_threshold to skip reporting on first N attempts ([#2503](https://github.com/getsentry/sentry-ruby/pull/2503))
- Support `code.namespace` for Ruby 3.4+ stacktraces ([#2506](https://github.com/getsentry/sentry-ruby/pull/2506))
- Support report_after_job_retries for activejob ([#2500](https://github.com/getsentry/sentry-ruby/pull/2500))

### Bug fixes

Expand Down
41 changes: 32 additions & 9 deletions sentry-rails/lib/sentry/rails/active_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
class SentryReporter
OP_NAME = "queue.active_job"
SPAN_ORIGIN = "auto.queue.active_job"

NOTIFICATION_NAME = "retry_stopped.active_job"
class << self
def record(job, &block)
Sentry.with_scope do |scope|
Expand All @@ -46,19 +46,42 @@
rescue Exception => e # rubocop:disable Lint/RescueException
finish_sentry_transaction(transaction, 500)

Sentry::Rails.capture_exception(
e,
extra: sentry_context(job),
tags: {
job_id: job.job_id,
provider_job_id: job.provider_job_id
}
)
unless Sentry.configuration.rails.active_job_report_after_job_retries
capture_exception(job, e)
end

raise
end
end
end

def capture_exception(job, e)
Sentry::Rails.capture_exception(
e,
extra: sentry_context(job),
tags: {
job_id: job.job_id,
provider_job_id: job.provider_job_id
}
)
end

def register_retry_stopped_subscriber
ActiveSupport::Notifications.subscribe(NOTIFICATION_NAME) do |*args|
retry_stopped_handler(*args)

Check warning on line 71 in sentry-rails/lib/sentry/rails/active_job.rb

View check run for this annotation

Codecov / codecov/patch

sentry-rails/lib/sentry/rails/active_job.rb#L71

Added line #L71 was not covered by tests
end
end

def retry_stopped_handler(*args)
event = ActiveSupport::Notifications::Event.new(*args)
job = event.payload[:job]
error = event.payload[:error]

Check warning on line 78 in sentry-rails/lib/sentry/rails/active_job.rb

View check run for this annotation

Codecov / codecov/patch

sentry-rails/lib/sentry/rails/active_job.rb#L76-L78

Added lines #L76 - L78 were not covered by tests

return if !Sentry.initialized? || job.already_supported_by_sentry_integration?
return unless Sentry.configuration.rails.active_job_report_after_job_retries
capture_exception(job, error)

Check warning on line 82 in sentry-rails/lib/sentry/rails/active_job.rb

View check run for this annotation

Codecov / codecov/patch

sentry-rails/lib/sentry/rails/active_job.rb#L80-L82

Added lines #L80 - L82 were not covered by tests
end

def finish_sentry_transaction(transaction, status)
return unless transaction

Expand Down
5 changes: 5 additions & 0 deletions sentry-rails/lib/sentry/rails/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,10 @@ class Configuration
# @return [Hash<String, Array<Symbol>>]
attr_accessor :active_support_logger_subscription_items

# Set this option to true if you want Sentry to only capture the last job
# retry if it fails.
attr_accessor :active_job_report_after_job_retries

def initialize
@register_error_subscriber = false
@report_rescued_exceptions = true
Expand All @@ -172,6 +176,7 @@ def initialize
@enable_db_query_source = true
@db_query_source_threshold_ms = 100
@active_support_logger_subscription_items = Sentry::Rails::ACTIVE_SUPPORT_LOGGER_SUBSCRIPTION_ITEMS_DEFAULT.dup
@active_job_report_after_job_retries = false
end
end
end
Expand Down
6 changes: 6 additions & 0 deletions sentry-rails/lib/sentry/rails/railtie.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ class Railtie < ::Rails::Railtie
activate_tracing

register_error_subscriber(app) if ::Rails.version.to_f >= 7.0 && Sentry.configuration.rails.register_error_subscriber

register_retry_stopped_subscriber if defined?(ActiveJob)
end

runner do
Expand Down Expand Up @@ -137,5 +139,9 @@ def register_error_subscriber(app)
require "sentry/rails/error_subscriber"
app.executor.error_reporter.subscribe(Sentry::Rails::ErrorSubscriber.new)
end

def register_retry_stopped_subscriber
Sentry::Rails::ActiveJobExtensions::SentryReporter.register_retry_stopped_subscriber
end
end
end
44 changes: 43 additions & 1 deletion sentry-rails/spec/sentry/rails/activejob_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ class FailedJobWithCron < FailedJob
sentry_monitor_check_ins slug: "failed_job", monitor_config: Sentry::Cron::MonitorConfig.from_crontab("5 * * * *")
end

class FailedJobWithRetryOn < FailedJob
if respond_to? :retry_on
retry_on StandardError, attempts: 3, wait: 0
end
end

RSpec.describe "without Sentry initialized", type: :job do
it "runs job" do
Expand Down Expand Up @@ -318,7 +323,6 @@ def perform(event, hint)

it "does not trigger sentry and re-raises" do
expect { FailedJob.perform_now }.to raise_error(FailedJob::TestError)

expect(transport.events.size).to eq(0)
end
end
Expand Down Expand Up @@ -386,4 +390,42 @@ def perform(event, hint)
end
end
end

describe "active_job_report_after_job_retries", skip: Rails.version.to_f < 5.1 do
before do
allow(Sentry::Rails::ActiveJobExtensions::SentryReporter)
.to receive(:capture_exception)
.and_call_original
end
context "when active_job_report_after_job_retries is false" do
it "reports 3 exceptions" do
assert_performed_jobs 3 do
FailedJobWithRetryOn.perform_later rescue nil
end

expect(Sentry::Rails::ActiveJobExtensions::SentryReporter)
.to have_received(:capture_exception)
.exactly(3).times
end
end
context "when active_job_report_after_job_retries is true" do
before do
Sentry.configuration.rails.active_job_report_after_job_retries = true
end

after do
Sentry.configuration.rails.active_job_report_after_job_retries = false
end

it "reports 1 exception" do
assert_performed_jobs 3 do
FailedJobWithRetryOn.perform_later rescue nil
end

expect(Sentry::Rails::ActiveJobExtensions::SentryReporter)
.to have_received(:capture_exception)
.exactly(1).times
end
end
end
end
6 changes: 6 additions & 0 deletions sentry-rails/spec/sentry/rails/configuration_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,10 @@ class MySubscriber; end
expect(subject.active_support_logger_subscription_items["foo"]).to include(:bar)
end
end

describe "#active_job_report_after_job_retries" do
it "has correct default value" do
expect(subject.active_job_report_after_job_retries).to eq(false)
end
end
end
Loading