Skip to content

Commit 98ba9d9

Browse files
authored
Merge pull request #1104 from appsignal/sidekiq-error-on-discard
Report Sidekiq errors when the job is discarded
2 parents 2478eb1 + 500b2b4 commit 98ba9d9

File tree

7 files changed

+273
-37
lines changed

7 files changed

+273
-37
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
bump: minor
3+
type: add
4+
---
5+
6+
Report Sidekiq errors when a job is dead/discarded. Configure the new `sidekiq_report_errors` config option to "discard" to only report errors when the job is not retried further.

lib/appsignal/config.rb

+8
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ class Config
4747
],
4848
:send_environment_metadata => true,
4949
:send_params => true,
50+
:sidekiq_report_errors => "all",
5051
:transaction_debug_mode => false
5152
}.freeze
5253

@@ -108,6 +109,7 @@ class Config
108109
"APPSIGNAL_SEND_ENVIRONMENT_METADATA" => :send_environment_metadata,
109110
"APPSIGNAL_SEND_PARAMS" => :send_params,
110111
"APPSIGNAL_SEND_SESSION_DATA" => :send_session_data,
112+
"APPSIGNAL_SIDEKIQ_REPORT_ERRORS" => :sidekiq_report_errors,
111113
"APPSIGNAL_SKIP_SESSION_DATA" => :skip_session_data,
112114
"APPSIGNAL_STATSD_PORT" => :statsd_port,
113115
"APPSIGNAL_TRANSACTION_DEBUG_MODE" => :transaction_debug_mode,
@@ -130,6 +132,7 @@ class Config
130132
APPSIGNAL_LOGGING_ENDPOINT
131133
APPSIGNAL_PUSH_API_ENDPOINT
132134
APPSIGNAL_PUSH_API_KEY
135+
APPSIGNAL_SIDEKIQ_REPORT_ERRORS
133136
APPSIGNAL_STATSD_PORT
134137
APPSIGNAL_WORKING_DIRECTORY_PATH
135138
APPSIGNAL_WORKING_DIR_PATH
@@ -563,6 +566,11 @@ def determine_overrides
563566
config[:activejob_report_errors] = "all"
564567
end
565568

569+
if config_hash[:sidekiq_report_errors] == "discard" &&
570+
!Appsignal::Hooks::SidekiqHook.version_5_1_or_higher?
571+
config[:sidekiq_report_errors] = "all"
572+
end
573+
566574
config
567575
end
568576

lib/appsignal/hooks/sidekiq.rb

+18-1
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,34 @@ class Hooks
55
class SidekiqHook < Appsignal::Hooks::Hook
66
register :sidekiq
77

8-
def dependencies_present?
8+
def self.version_5_1_or_higher?
9+
@version_5_1_or_higher ||=
10+
if dependencies_present?
11+
Gem::Version.new(::Sidekiq::VERSION) >= Gem::Version.new("5.1.0")
12+
else
13+
false
14+
end
15+
end
16+
17+
def self.dependencies_present?
918
defined?(::Sidekiq)
1019
end
1120

21+
def dependencies_present?
22+
self.class.dependencies_present?
23+
end
24+
1225
def install
1326
require "appsignal/integrations/sidekiq"
1427
Appsignal::Probes.register :sidekiq, Appsignal::Probes::SidekiqProbe
1528

1629
::Sidekiq.configure_server do |config|
1730
config.error_handlers <<
1831
Appsignal::Integrations::SidekiqErrorHandler.new
32+
if config.respond_to? :death_handlers
33+
config.death_handlers <<
34+
Appsignal::Integrations::SidekiqDeathHandler.new
35+
end
1936

2037
config.server_middleware do |chain|
2138
if chain.respond_to? :prepend

lib/appsignal/integrations/sidekiq.rb

+37-18
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,51 @@
44

55
module Appsignal
66
module Integrations
7+
# Handler for job death events. We get notified when a job has exhausted
8+
# its retries.
9+
#
10+
# This is called before the SidekiqErrorHandler so it doesn't need to worry
11+
# about completing the transaction.
12+
#
13+
# Introduced in Sidekiq 5.1.
14+
class SidekiqDeathHandler
15+
def call(_job_context, exception)
16+
return unless Appsignal.config[:sidekiq_report_errors] == "discard"
17+
18+
transaction = Appsignal::Transaction.current
19+
transaction.set_error(exception)
20+
end
21+
end
22+
723
# Error handler for Sidekiq to report errors from jobs and internal Sidekiq
824
# errors.
925
#
1026
# @api private
1127
class SidekiqErrorHandler
28+
# Sidekiq 7.1.5 introduced the third sidekiq_config argument. It is not
29+
# given on older Sidekiq versions.
1230
def call(exception, sidekiq_context, _sidekiq_config = nil)
13-
transaction =
14-
if Appsignal::Transaction.current?
15-
Appsignal::Transaction.current
16-
else
17-
# Sidekiq error outside of the middleware scope.
18-
# Can be a job JSON parse error or some other error happening in
19-
# Sidekiq.
20-
transaction =
21-
Appsignal::Transaction.create(
22-
SecureRandom.uuid, # Newly generated job id
23-
Appsignal::Transaction::BACKGROUND_JOB,
24-
Appsignal::Transaction::GenericRequest.new({})
25-
)
26-
transaction.set_action_if_nil("SidekiqInternal")
27-
transaction.set_metadata("sidekiq_error", sidekiq_context[:context])
28-
transaction.params = { :jobstr => sidekiq_context[:jobstr] }
29-
transaction
31+
if Appsignal::Transaction.current?
32+
if Appsignal.config[:sidekiq_report_errors] == "all"
33+
transaction = Appsignal::Transaction.current
34+
transaction.set_error(exception)
3035
end
36+
else
37+
# Sidekiq error outside of the middleware scope.
38+
# Can be a job JSON parse error or some other error happening in
39+
# Sidekiq.
40+
transaction =
41+
Appsignal::Transaction.create(
42+
SecureRandom.uuid, # Newly generated job id
43+
Appsignal::Transaction::BACKGROUND_JOB,
44+
Appsignal::Transaction::GenericRequest.new({})
45+
)
46+
transaction.set_action_if_nil("SidekiqInternal")
47+
transaction.set_metadata("sidekiq_error", sidekiq_context[:context])
48+
transaction.params = { :jobstr => sidekiq_context[:jobstr] }
49+
transaction.set_error(exception)
50+
end
3151

32-
transaction.set_error(exception)
3352
Appsignal::Transaction.complete_current!
3453
end
3554
end

spec/lib/appsignal/config_spec.rb

+28
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@
187187
:send_environment_metadata => true,
188188
:send_params => true,
189189
:send_session_data => true,
190+
:sidekiq_report_errors => "all",
190191
:transaction_debug_mode => false
191192
)
192193
end
@@ -583,6 +584,33 @@
583584
end
584585
end
585586
end
587+
588+
context "sidekiq_report_errors" do
589+
let(:config_options) { { :sidekiq_report_errors => "discard" } }
590+
before do
591+
if Appsignal::Hooks::SidekiqHook.instance_variable_defined?(:@version_5_1_or_higher)
592+
Appsignal::Hooks::SidekiqHook.remove_instance_variable(:@version_5_1_or_higher)
593+
end
594+
end
595+
596+
context "when Sidekiq >= 5.1 and 'discard'" do
597+
before { stub_const("Sidekiq::VERSION", "5.1.0") }
598+
599+
it "does not override the sidekiq_report_errors value" do
600+
expect(config[:sidekiq_report_errors]).to eq("discard")
601+
expect(config.override_config[:sidekiq_report_errors]).to be_nil
602+
end
603+
end
604+
605+
context "when Sidekiq < 5.1 and 'discard'" do
606+
before { stub_const("Sidekiq::VERSION", "5.0.0") }
607+
608+
it "sets sidekiq_report_errors to 'all'" do
609+
expect(config[:sidekiq_report_errors]).to eq("all")
610+
expect(config.override_config[:sidekiq_report_errors]).to eq("all")
611+
end
612+
end
613+
end
586614
end
587615

588616
describe "config keys" do

0 commit comments

Comments
 (0)