11# frozen_string_literal: true
22
33require "sentry/sidekiq/context_filter"
4+ require "sentry/sidekiq/failure_reporting"
5+ require "sentry/sidekiq/sentry_context_middleware"
46
57module Sentry
68 module Sidekiq
79 class ErrorHandler
8- WITH_SIDEKIQ_7 = ::Gem ::Version . new ( ::Sidekiq ::VERSION ) >= ::Gem ::Version . new ( "7.0" )
10+ def initialize ( failure_reporting : FailureReporting . new , consumer : SentryContextServerMiddleware . consumer , job_extension : Sentry ::Sidekiq . job_extension )
11+ @failure_reporting = failure_reporting
12+ @consumer = consumer
13+ @job_extension = job_extension
14+ end
915
1016 # @param ex [Exception] the exception / error that occured
1117 # @param context [Hash or Array] Sidekiq error context
@@ -16,83 +22,19 @@ class ErrorHandler
1622 def call ( ex , context , sidekiq_config = nil )
1723 return unless Sentry . initialized?
1824
19- context_filter = Sentry ::Sidekiq ::ContextFilter . new ( context )
20-
2125 scope = Sentry . get_current_scope
22- scope . set_transaction_name ( context_filter . transaction_name , source : :task ) unless scope . transaction_name
23-
24- retry_lim = retry_limit ( context , sidekiq_config )
25-
26- # If Sentry is configured to only report an error _after_ all retries have been exhausted,
27- # and if the job is retryable, and have not exceeded the retry_limit,
28- # return early.
29- if Sentry . configuration . sidekiq . report_after_job_retries && retryable? ( context )
30- retry_count = context . dig ( :job , "retry_count" )
31- if retry_count . nil? || retry_count < retry_lim - 1
32- return
33- end
34- end
35-
36- # See if we want to ignore jobs that have dead: false
37- return if Sentry . configuration . sidekiq . report_only_dead_jobs && context . dig ( :job , "dead" ) == false
38-
39- # Check if the retry count is below the attempt_threshold
40- attempt_threshold = context . dig ( :job , "attempt_threshold" )
41- if attempt_threshold && retryable? ( context )
42- attempt_threshold = attempt_threshold . to_i
43- retry_count = context . dig ( :job , "retry_count" )
44- # attempt 1 - retry_count is nil
45- # attempt 2 - this is your first retry so retry_count is 0
46- # attempt 3 - you have retried once, retry_count is 1
47- attempt = retry_count . nil? ? 1 : retry_count . to_i + 2
48- # Cap at the final attempt so jobs with fewer retries than the threshold still report.
49- effective_threshold = [ attempt_threshold , retry_lim + 1 ] . min
26+ scope . set_transaction_name ( @job_extension . error_context_transaction_name ( context ) , source : :task ) unless scope . transaction_name
5027
51- return if attempt < effective_threshold
52- end
28+ job = context [ :job ]
29+ return unless @failure_reporting . report? ( job , sidekiq_config )
5330
54- Sentry ::Sidekiq . capture_exception (
55- ex ,
56- contexts : { sidekiq : context_filter . filtered } ,
57- hint : { background : false }
31+ @consumer . capture_exception (
32+ job , ex ,
33+ contexts : { sidekiq : ContextFilter . new ( context ) . filtered }
5834 )
5935 ensure
6036 scope &.clear
6137 end
62-
63- private
64-
65- def retryable? ( context )
66- retry_option = context . dig ( :job , "retry" )
67- # when `retry` is not specified, it's default is `true` and it means 25 retries.
68- retry_option . nil? || retry_option == true || ( retry_option . is_a? ( Integer ) && retry_option . positive? )
69- end
70-
71- # @return [Integer] the number of retries allowed for the job
72- # Tries to fetch the retry limit from the job config first,
73- # then falls back to Sidekiq's configuration.
74- def retry_limit ( context , sidekiq_config )
75- limit = context . dig ( :job , "retry" )
76-
77- case limit
78- when Integer
79- limit
80- when TrueClass , NilClass
81- max_retries =
82- if WITH_SIDEKIQ_7
83- # Sidekiq 7.1.5+ passes the config to the error handler, so we should use that.
84- # Sidekiq 7.0 -> 7.1.5 provides ::Sidekiq.default_configuration.
85- sidekiq_config . is_a? ( ::Sidekiq ::Config ) ?
86- sidekiq_config [ :max_retries ] :
87- ::Sidekiq . default_configuration [ :max_retries ]
88- else
89- ::Sidekiq . options [ :max_retries ]
90- end
91- max_retries || 25
92- else
93- 0
94- end
95- end
9638 end
9739 end
9840end
0 commit comments