Skip to content

Commit 50da25c

Browse files
Merge pull request #3317 from newrelic/sidekiq_retry_backup
Add `sidekiq.ignore_retry_errors` to defer error reporting
2 parents 0f7ccf4 + 6447247 commit 50da25c

File tree

11 files changed

+304
-2
lines changed

11 files changed

+304
-2
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## dev
44

5+
- **Feature: Add sidekiq.ignore_retry_errors configuration option**
6+
7+
A new configuration option, `sidekiq.ignore_retry_errors`, has been added to control if Sidekiq job retries are captured. Retry errors are captured by default, but now if `sidekiq.ignore_retry_errors` is set to `true`, the agent will ignore exceptions raised during Sidekiq's retry attempts and will only report the error if the job permanently fails. Thank you [DonGiulio](https://github.com/DonGiulio) for recognizing this improvement and contributing a solution. [PR#3317](https://github.com/newrelic/newrelic-ruby-agent/pull/3317)
8+
59
- **Feature: Deprecation notice for recording deployments using Capistrano**
610

711
Sending application deployment information using a Capistrano recipe is deprecated and will be removed in agent version 10.0.0. For recording deployments, please see our guide to [Change Tracking](https://docs.newrelic.com/docs/change-tracking/change-tracking-introduction/) for a list of available options.

lib/new_relic/agent/configuration/default_source.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2140,6 +2140,13 @@ def self.enforce_fallback(allowed_values: nil, fallback: nil)
21402140
argument array elements and job argument scalars will be excluded.
21412141
SIDEKIQ_ARGS_EXCLUDE
21422142
},
2143+
:'sidekiq.ignore_retry_errors' => {
2144+
:default => false,
2145+
:public => true,
2146+
:type => Boolean,
2147+
:allowed_from_server => false,
2148+
:description => %Q(If `true`, the agent will ignore exceptions raised during Sidekiq's retry attempts and will only report the error if the job permanently fails.)
2149+
},
21432150
# Slow SQL
21442151
:'slow_sql.enabled' => {
21452152
:default => value_of(:'transaction_tracer.enabled'),

lib/new_relic/agent/instrumentation/sidekiq.rb

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,19 @@
4040
end
4141
end
4242

43-
if config.respond_to?(:error_handlers)
43+
if config.respond_to?(:error_handlers) && !NewRelic::Agent.config[:'sidekiq.ignore_retry_errors']
4444
# Sidekiq 3.0.0 - 7.1.4 expect error_handlers to have 2 arguments
4545
# Sidekiq 7.1.5+ expect error_handlers to have 3 arguments
4646
config.error_handlers << proc do |error, _ctx, *_|
4747
NewRelic::Agent.notice_error(error)
4848
end
4949
end
50+
51+
if config.respond_to?(:death_handlers) && NewRelic::Agent.config[:'sidekiq.ignore_retry_errors']
52+
config.death_handlers << proc do |_, error|
53+
NewRelic::Agent.notice_error(error)
54+
end
55+
end
5056
end
5157
end
5258
end

newrelic.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,10 @@ common: &default_settings
331331
# If true, disables Sidekiq instrumentation.
332332
# disable_sidekiq: false
333333

334+
# 'If true, the agent will ignore exceptions raised during Sidekiq's retry attempts and will only report the
335+
# error if the job permanently fails.
336+
# sidekiq.ignore_retry_errors: false
337+
334338
# If true, disables agent middleware for Sinatra. This middleware is responsible
335339
# for advanced feature support such as cross application tracing, page load
336340
# timing, and error collection.

test/multiverse/lib/multiverse/runner.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ def execute_suites(filter, opts)
110110

111111
# these need services running in github actions, so they are separated
112112
'services_1' => %w[mongo bunny],
113-
'services_2' => %w[redis sidekiq sidekiq_delay_extensions memcache],
113+
'services_2' => %w[redis sidekiq sidekiq_delay_extensions sidekiq_ignore_retry_errors_enabled memcache],
114114
'services_kafka' => %w[rdkafka ruby_kafka],
115115
'services_elasticsearch' => %w[elasticsearch],
116116
'services_mysql_pg' => %w[active_record active_record_pg],
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# This file is distributed under New Relic's license terms.
2+
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3+
# frozen_string_literal: true
4+
5+
require_relative 'sidekiq_test_helpers'
6+
7+
# On startup, Sidekiq instrumentation registers error and death handlers
8+
# based on the value of the 'sidekiq.ignore_retry_errors'. Because of this,
9+
# we need to have separate enabled/disabled test suites to test both cases.
10+
class SidekiqIgnoreRetryErrorsTest < Minitest::Test
11+
include SidekiqTestHelpers
12+
13+
def test_sidekiq_ignore_retry_errors_default_value
14+
refute NewRelic::Agent.config[:'sidekiq.ignore_retry_errors'],
15+
'Expected sidekiq.ignore_retry_errors default to be false'
16+
end
17+
18+
def test_sidekiq_ignore_retry_errors_configuration_can_be_set_to_true
19+
with_config(:'sidekiq.ignore_retry_errors' => true) do
20+
assert NewRelic::Agent.config[:'sidekiq.ignore_retry_errors'],
21+
'Expected sidekiq.ignore_retry_errors to be true when configured'
22+
end
23+
end
24+
25+
def test_sidekiq_ignore_retry_errors_configuration_can_be_set_to_false
26+
with_config(:'sidekiq.ignore_retry_errors' => false) do
27+
refute NewRelic::Agent.config[:'sidekiq.ignore_retry_errors'],
28+
'Expected sidekiq.ignore_retry_errors to be false when configured'
29+
end
30+
end
31+
32+
def test_error_handlers_registered_when_sidekiq_ignore_retry_errors_is_false
33+
# TODO: MAJOR VERSION - remove this when Sidekiq v5 is no longer supported
34+
skip 'Test requires Sidekiq v6+' unless Sidekiq::VERSION.split('.').first.to_i >= 6
35+
36+
config = if Sidekiq::VERSION.split('.').first.to_i >= 7
37+
Sidekiq.default_configuration
38+
else
39+
Sidekiq
40+
end
41+
42+
error_handlers = if config.respond_to?(:error_handlers)
43+
config.error_handlers
44+
else
45+
config[:error_handlers] || []
46+
end
47+
48+
nr_error_handler_found = error_handlers.any? do |handler|
49+
handler.is_a?(Proc) && handler.source_location&.first&.include?('newrelic')
50+
end
51+
52+
assert nr_error_handler_found,
53+
'Expected NewRelic error_handler to be registered when sidekiq.ignore_retry_errors is false'
54+
end
55+
56+
def test_death_handlers_not_registered_when_sidekiq_ignore_retry_errors_is_false
57+
# TODO: MAJOR VERSION - remove this when Sidekiq v5 is no longer supported
58+
skip 'Test requires Sidekiq v6+' unless Sidekiq::VERSION.split('.').first.to_i >= 6
59+
60+
config = if Sidekiq::VERSION.split('.').first.to_i >= 7
61+
Sidekiq.default_configuration
62+
else
63+
Sidekiq
64+
end
65+
66+
death_handlers = if config.respond_to?(:death_handlers)
67+
config.death_handlers
68+
else
69+
config[:death_handlers] || []
70+
end
71+
72+
nr_death_handler_found = death_handlers.any? do |handler|
73+
handler.is_a?(Proc) && handler.source_location&.first&.include?('newrelic')
74+
end
75+
76+
refute nr_death_handler_found,
77+
'Expected NewRelic death_handler to NOT be registered when sidekiq.ignore_retry_errors is false'
78+
end
79+
end

test/multiverse/suites/sidekiq/sidekiq_instrumentation_test.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,8 @@ def test_works_with_perform_inline
7070
assert_equal 1, segments.size, "Expected to find a single Sidekiq job segment, found #{segments.size}"
7171
end
7272
end
73+
74+
def test_sidekiq_ignore_retry_errors_default_is_false
75+
refute NewRelic::Agent.config[:'sidekiq.ignore_retry_errors'], 'Expected default value for sidekiq.ignore_retry_errors to be false'
76+
end
7377
end
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# This file is distributed under New Relic's license terms.
2+
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3+
# frozen_string_literal: true
4+
5+
SIDEKIQ_VERSIONS = [
6+
[nil, 3.2],
7+
['7.3.9', 2.7],
8+
['6.4.0', 2.5],
9+
['5.0.3', 2.4, 2.5]
10+
]
11+
12+
def gem_list(sidekiq_version = nil)
13+
<<-RB
14+
gem 'sidekiq'#{sidekiq_version}
15+
gem 'newrelic_rpm', :require => false, :path => File.expand_path('../../../../')
16+
RB
17+
end
18+
19+
create_gemfiles(SIDEKIQ_VERSIONS)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
development:
3+
error_collector:
4+
enabled: true
5+
apdex_t: 0.5
6+
monitor_mode: true
7+
license_key: bootstrap_newrelic_admin_license_key_000
8+
app_name: test
9+
ca_bundle_path: ../../../config/test.cert.crt
10+
app_name: test
11+
host: localhost
12+
api_host: localhost
13+
port: <%= $collector && $collector.port %>
14+
transaction_tracer:
15+
record_sql: obfuscated
16+
enabled: true
17+
stack_trace_threshold: 0.5
18+
transaction_threshold: 1.0
19+
capture_params: false
20+
log_file_path: log
21+
sidekiq.ignore_retry_errors: true
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# This file is distributed under New Relic's license terms.
2+
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3+
# frozen_string_literal: true
4+
5+
require_relative 'sidekiq_test_helpers'
6+
7+
# On startup, Sidekiq instrumentation registers error and death handlers
8+
# based on the value of the 'sidekiq.ignore_retry_errors'. Because of this,
9+
# we need to have separate enabled/disabled test suites to test both cases.
10+
class SidekiqIgnoreRetryErrorEnabledTest < Minitest::Test
11+
include SidekiqTestHelpers
12+
13+
def test_error_handlers_not_registered_when_sidekiq_ignore_retry_errors_is_true
14+
# TODO: MAJOR VERSION - remove this when Sidekiq v5 is no longer supported
15+
skip 'Test requires Sidekiq v6+' unless Sidekiq::VERSION.split('.').first.to_i >= 6
16+
17+
config = if Sidekiq::VERSION.split('.').first.to_i >= 7
18+
Sidekiq.default_configuration
19+
else
20+
Sidekiq
21+
end
22+
23+
error_handlers = if config.respond_to?(:error_handlers)
24+
config.error_handlers
25+
else
26+
config[:error_handlers] || []
27+
end
28+
29+
nr_error_handler_found = error_handlers.any? do |handler|
30+
handler.is_a?(Proc) && handler.source_location&.first&.include?('newrelic')
31+
end
32+
33+
refute nr_error_handler_found,
34+
'Expected NewRelic error_handler to NOT be registered when sidekiq.ignore_retry_errors is true'
35+
end
36+
37+
def test_death_handlers_registered_when_sidekiq_ignore_retry_errors_is_true
38+
# TODO: MAJOR VERSION - remove this when Sidekiq v5 is no longer supported
39+
skip 'Test requires Sidekiq v6+' unless Sidekiq::VERSION.split('.').first.to_i >= 6
40+
41+
config = if Sidekiq::VERSION.split('.').first.to_i >= 7
42+
Sidekiq.default_configuration
43+
else
44+
Sidekiq
45+
end
46+
47+
death_handlers = if config.respond_to?(:death_handlers)
48+
config.death_handlers
49+
else
50+
config[:death_handlers] || []
51+
end
52+
53+
nr_death_handler_found = death_handlers.any? do |handler|
54+
handler.is_a?(Proc) && handler.source_location&.first&.include?('newrelic')
55+
end
56+
57+
assert nr_death_handler_found,
58+
'Expected NewRelic death_handler to be registered when sidekiq.ignore_retry_errors is true'
59+
end
60+
61+
def test_basic_job_execution_still_works
62+
segment = run_job
63+
64+
assert_predicate segment, :finished?
65+
assert_predicate segment, :record_metrics?
66+
assert_kind_of Float, segment.duration
67+
end
68+
end

0 commit comments

Comments
 (0)