sentry-sidekiq 5.3.1 → 5.16.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e8732abbcde88b2a9399b0c4b81b1dda8837fb688b3de5c08138e53660c7d41c
4
- data.tar.gz: 1e3a534cd890ad29e3cfe92696cd60fee88f1dd618b1c3e35a348c8c9e34e1c9
3
+ metadata.gz: 99c7773fed4941672765e6032cd6fa034ede2fa1af7ddcbe717d696e7e73f96d
4
+ data.tar.gz: c059026ff1fb540d7bb7b47ab358a842d1ef2473ae9a32b8114663bead468be0
5
5
  SHA512:
6
- metadata.gz: 0cdbbcb530b5e91e37d85072ba2510788ea522211d81521f07f60664656e3427df07357084d346b3cbc1721ceb27438b6236173750e9b6e8ee908759779483bf
7
- data.tar.gz: 80f966439ea52e3d869f2a40d914ceb63028216b6ede3c9e84735c8052a42773c47c4da58eb061d1dfb3932aa70ec7cf07c46ef7a04182639cba729309d7d4ac
6
+ metadata.gz: d9249aa9401c67882c6a015eb0346e4e7c916399d1ea2e2175d7b72ef49c2c4cf6cc5ae2ae84a2855bd2dd5969cd7729cd4bfc9f526b42f8e397a3f4bcaf2c89
7
+ data.tar.gz: 944851f9e32d13bd327e1efb4a4dc42c2d24fffd7d408afce9be5342a6b229ee383edfe07a73076b5d527296db4807f98034e3c6c0a529c7986737f0a5b55e93
data/Gemfile CHANGED
@@ -3,23 +3,27 @@ git_source(:github) { |name| "https://github.com/#{name}.git" }
3
3
 
4
4
  # Specify your gem's dependencies in sentry-ruby.gemspec
5
5
  gemspec
6
+ gem "sentry-ruby", path: "../sentry-ruby"
7
+ gem "sentry-rails", path: "../sentry-rails"
8
+
9
+ # https://github.com/flavorjones/loofah/pull/267
10
+ # loofah changed the required ruby version in a patch so we need to explicitly pin it
11
+ gem "loofah", "2.20.0" if RUBY_VERSION.to_f < 2.5
6
12
 
7
- gem "rake", "~> 12.0"
8
- gem "rspec", "~> 3.0"
9
- gem 'simplecov'
10
- gem "simplecov-cobertura", "~> 1.4"
11
- gem "rexml"
13
+ # For https://github.com/ruby/psych/issues/655
14
+ gem "psych", "5.1.0"
12
15
 
13
16
  sidekiq_version = ENV["SIDEKIQ_VERSION"]
14
- sidekiq_version = "6.0" if sidekiq_version.nil?
17
+ sidekiq_version = "7.0" if sidekiq_version.nil?
18
+ sidekiq_version = Gem::Version.new(sidekiq_version)
15
19
 
16
- gem "rails", "< 7.0"
17
20
  gem "sidekiq", "~> #{sidekiq_version}"
18
21
 
19
- gem "sentry-ruby", path: "../sentry-ruby"
20
- gem "sentry-rails", path: "../sentry-rails"
22
+ if RUBY_VERSION.to_f >= 2.7 && sidekiq_version >= Gem::Version.new("6.0")
23
+ gem "sidekiq-cron"
24
+ gem "sidekiq-scheduler"
25
+ end
21
26
 
22
- gem "object_tracer"
23
- gem "debug", github: "ruby/debug", platform: :ruby if RUBY_VERSION.to_f >= 2.6
24
- gem "pry"
27
+ gem "rails", "> 5.0.0", "< 7.1.0"
25
28
 
29
+ eval_gemfile File.expand_path("../Gemfile", __dir__)
data/README.md CHANGED
@@ -11,7 +11,7 @@
11
11
 
12
12
 
13
13
  [![Gem Version](https://img.shields.io/gem/v/sentry-sidekiq.svg)](https://rubygems.org/gems/sentry-sidekiq)
14
- ![Build Status](https://github.com/getsentry/sentry-ruby/workflows/sentry-sidekiq%20Test/badge.svg)
14
+ ![Build Status](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_sidekiq_test.yml/badge.svg)
15
15
  [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master)
16
16
  [![Gem](https://img.shields.io/gem/dt/sentry-sidekiq.svg)](https://rubygems.org/gems/sentry-sidekiq/)
17
17
  [![SemVer](https://api.dependabot.com/badges/compatibility_score?dependency-name=sentry-sidekiq&package-manager=bundler&version-scheme=semver)](https://dependabot.com/compatibility-score.html?dependency-name=sentry-sidekiq&package-manager=bundler&version-scheme=semver)
@@ -26,6 +26,9 @@ module Sentry
26
26
  end
27
27
  end
28
28
 
29
+ # Sidekiq 7.0 started adding `_config` to the context, which is not easily serialisable
30
+ # And it's presence could be confusing so it's better to remove it until we decided to add it for a reason
31
+ filtered_context.delete(:_config)
29
32
  filtered_context
30
33
  end
31
34
 
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Try requiring sidekiq-cron to ensure it's loaded before the integration.
4
+ # If sidekiq-cron is not available, do nothing.
5
+ begin
6
+ require "sidekiq-cron"
7
+ rescue LoadError
8
+ return
9
+ end
10
+
11
+ module Sentry
12
+ module Sidekiq
13
+ module Cron
14
+ module Job
15
+ def save
16
+ # validation failed, do nothing
17
+ return false unless super
18
+
19
+ # fail gracefully if can't find class
20
+ klass_const =
21
+ begin
22
+ ::Sidekiq::Cron::Support.constantize(klass.to_s)
23
+ rescue NameError
24
+ return true
25
+ end
26
+
27
+ # only patch if not explicitly included in job by user
28
+ unless klass_const.send(:ancestors).include?(Sentry::Cron::MonitorCheckIns)
29
+ klass_const.send(:include, Sentry::Cron::MonitorCheckIns)
30
+ klass_const.send(:sentry_monitor_check_ins,
31
+ slug: name,
32
+ monitor_config: Sentry::Cron::MonitorConfig.from_crontab(cron))
33
+ end
34
+
35
+ true
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ Sentry.register_patch(:sidekiq_cron, Sentry::Sidekiq::Cron::Job, ::Sidekiq::Cron::Job)
@@ -3,17 +3,28 @@ require 'sentry/sidekiq/context_filter'
3
3
  module Sentry
4
4
  module Sidekiq
5
5
  class ErrorHandler
6
- def call(ex, context)
6
+ WITH_SIDEKIQ_7 = ::Gem::Version.new(::Sidekiq::VERSION) >= ::Gem::Version.new("7.0")
7
+
8
+ # @param ex [Exception] the exception / error that occured
9
+ # @param context [Hash or Array] Sidekiq error context
10
+ # @param sidekiq_config [Sidekiq::Config, Hash] Sidekiq configuration,
11
+ # Defaults to nil.
12
+ # Sidekiq will pass the config in starting Sidekiq 7.1.5, see
13
+ # https://github.com/sidekiq/sidekiq/pull/6051
14
+ def call(ex, context, sidekiq_config = nil)
7
15
  return unless Sentry.initialized?
8
16
 
9
17
  context_filter = Sentry::Sidekiq::ContextFilter.new(context)
10
18
 
11
19
  scope = Sentry.get_current_scope
12
- scope.set_transaction_name(context_filter.transaction_name) unless scope.transaction_name
20
+ scope.set_transaction_name(context_filter.transaction_name, source: :task) unless scope.transaction_name
13
21
 
22
+ # If Sentry is configured to only report an error _after_ all retries have been exhausted,
23
+ # and if the job is retryable, and have not exceeded the retry_limit,
24
+ # return early.
14
25
  if Sentry.configuration.sidekiq.report_after_job_retries && retryable?(context)
15
26
  retry_count = context.dig(:job, "retry_count")
16
- if retry_count.nil? || retry_count < retry_limit(context) - 1
27
+ if retry_count.nil? || retry_count < retry_limit(context, sidekiq_config) - 1
17
28
  return
18
29
  end
19
30
  end
@@ -23,6 +34,8 @@ module Sentry
23
34
  contexts: { sidekiq: context_filter.filtered },
24
35
  hint: { background: false }
25
36
  )
37
+ ensure
38
+ scope&.clear
26
39
  end
27
40
 
28
41
  private
@@ -33,14 +46,27 @@ module Sentry
33
46
  retry_option == true || (retry_option.is_a?(Integer) && retry_option.positive?)
34
47
  end
35
48
 
36
- def retry_limit(context)
49
+ # @return [Integer] the number of retries allowed for the job
50
+ # Tries to fetch the retry limit from the job config first,
51
+ # then falls back to Sidekiq's configuration.
52
+ def retry_limit(context, sidekiq_config)
37
53
  limit = context.dig(:job, "retry")
38
54
 
39
55
  case limit
40
56
  when Integer
41
57
  limit
42
58
  when TrueClass
43
- ::Sidekiq.options[:max_retries] || 25
59
+ max_retries =
60
+ if WITH_SIDEKIQ_7
61
+ # Sidekiq 7.1.5+ passes the config to the error handler, so we should use that.
62
+ # Sidekiq 7.0 -> 7.1.5 provides ::Sidekiq.default_configuration.
63
+ sidekiq_config.is_a?(::Sidekiq::Config) ?
64
+ sidekiq_config[:max_retries] :
65
+ ::Sidekiq.default_configuration[:max_retries]
66
+ else
67
+ ::Sidekiq.options[:max_retries]
68
+ end
69
+ max_retries || 25
44
70
  else
45
71
  0
46
72
  end
@@ -3,6 +3,8 @@ require 'sentry/sidekiq/context_filter'
3
3
  module Sentry
4
4
  module Sidekiq
5
5
  class SentryContextServerMiddleware
6
+ OP_NAME = "queue.sidekiq".freeze
7
+
6
8
  def call(_worker, job, queue)
7
9
  return yield unless Sentry.initialized?
8
10
 
@@ -16,8 +18,8 @@ module Sentry
16
18
  scope.set_tags(queue: queue, jid: job["jid"])
17
19
  scope.set_tags(build_tags(job["tags"]))
18
20
  scope.set_contexts(sidekiq: job.merge("queue" => queue))
19
- scope.set_transaction_name(context_filter.transaction_name)
20
- transaction = start_transaction(scope.transaction_name, job["sentry_trace"])
21
+ scope.set_transaction_name(context_filter.transaction_name, source: :task)
22
+ transaction = start_transaction(scope, job["trace_propagation_headers"])
21
23
  scope.set_span(transaction) if transaction
22
24
 
23
25
  begin
@@ -37,9 +39,9 @@ module Sentry
37
39
  Array(tags).each_with_object({}) { |name, tags_hash| tags_hash[:"sidekiq.#{name}"] = true }
38
40
  end
39
41
 
40
- def start_transaction(transaction_name, sentry_trace)
41
- options = { name: transaction_name, op: "sidekiq" }
42
- transaction = Sentry::Transaction.from_sentry_trace(sentry_trace, **options) if sentry_trace
42
+ def start_transaction(scope, env)
43
+ options = { name: scope.transaction_name, source: scope.transaction_source, op: OP_NAME }
44
+ transaction = Sentry.continue_trace(env, **options)
43
45
  Sentry.start_transaction(transaction: transaction, **options)
44
46
  end
45
47
 
@@ -56,9 +58,8 @@ module Sentry
56
58
  return yield unless Sentry.initialized?
57
59
 
58
60
  user = Sentry.get_current_scope.user
59
- transaction = Sentry.get_current_scope.get_transaction
60
61
  job["sentry_user"] = user unless user.empty?
61
- job["sentry_trace"] = transaction.to_sentry_trace if transaction
62
+ job["trace_propagation_headers"] ||= Sentry.get_trace_propagation_headers
62
63
  yield
63
64
  end
64
65
  end
@@ -1,5 +1,5 @@
1
1
  module Sentry
2
2
  module Sidekiq
3
- VERSION = "5.3.1"
3
+ VERSION = "5.16.1"
4
4
  end
5
5
  end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Try to require sidekiq-scheduler to make sure it's loaded before the integration.
4
+ begin
5
+ require "sidekiq-scheduler"
6
+ rescue LoadError
7
+ return
8
+ end
9
+
10
+ # If we've loaded sidekiq-scheduler, but the API changed,
11
+ # and the Scheduler class is not there, fail gracefully.
12
+ return unless defined?(::SidekiqScheduler::Scheduler)
13
+
14
+ module Sentry
15
+ module SidekiqScheduler
16
+ module Scheduler
17
+ def new_job(name, interval_type, config, schedule, options)
18
+ # Schedule the job upstream first
19
+ # SidekiqScheduler does not validate schedules
20
+ # It will fail with an error if the schedule in the config is invalid.
21
+ # If this errors out, let it fall through.
22
+ rufus_job = super
23
+
24
+ klass = config.fetch("class")
25
+ return rufus_job unless klass
26
+
27
+ # Constantize the job class, and fail gracefully if it could not be found
28
+ klass_const =
29
+ begin
30
+ Object.const_get(klass)
31
+ rescue NameError
32
+ return rufus_job
33
+ end
34
+
35
+ # For cron, every, or interval jobs — grab their schedule.
36
+ # Rufus::Scheduler::EveryJob stores it's frequency in seconds,
37
+ # so we convert it to minutes before passing in to the monitor.
38
+ monitor_config = case interval_type
39
+ when "cron"
40
+ # fugit is a second order dependency of sidekiq-scheduler via rufus-scheduler
41
+ parsed_cron = ::Fugit.parse_cron(schedule)
42
+ timezone = parsed_cron.timezone
43
+
44
+ # fugit supports having the timezone part of the cron string,
45
+ # so we need to pull that with some hacky stuff
46
+ if timezone
47
+ parsed_cron.instance_variable_set(:@timezone, nil)
48
+ cron_without_timezone = parsed_cron.to_cron_s
49
+ Sentry::Cron::MonitorConfig.from_crontab(cron_without_timezone, timezone: timezone.name)
50
+ else
51
+ Sentry::Cron::MonitorConfig.from_crontab(schedule)
52
+ end
53
+ when "every", "interval"
54
+ Sentry::Cron::MonitorConfig.from_interval(rufus_job.frequency.to_i / 60, :minute)
55
+ end
56
+
57
+ # If we couldn't build a monitor config, it's either an error, or
58
+ # it's a one-time job (interval_type is in, or at), in which case
59
+ # we should not make a monitof for it automaticaly.
60
+ return rufus_job if monitor_config.nil?
61
+
62
+ # only patch if not explicitly included in job by user
63
+ unless klass_const.send(:ancestors).include?(Sentry::Cron::MonitorCheckIns)
64
+ klass_const.send(:include, Sentry::Cron::MonitorCheckIns)
65
+ slug = klass_const.send(:sentry_monitor_slug, name: name)
66
+ klass_const.send(:sentry_monitor_check_ins,
67
+ slug: slug,
68
+ monitor_config: monitor_config)
69
+
70
+ ::Sidekiq.logger.info "Injected Sentry Crons monitor checkins into #{klass}"
71
+ end
72
+
73
+ rufus_job
74
+ end
75
+ end
76
+ end
77
+ end
78
+
79
+ Sentry.register_patch(:sidekiq_scheduler, Sentry::SidekiqScheduler::Scheduler, ::SidekiqScheduler::Scheduler)
@@ -39,3 +39,7 @@ Sidekiq.configure_client do |config|
39
39
  chain.add Sentry::Sidekiq::SentryContextClientMiddleware
40
40
  end
41
41
  end
42
+
43
+ # patches
44
+ require "sentry/sidekiq/cron/job"
45
+ require "sentry/sidekiq-scheduler/scheduler"
@@ -22,6 +22,6 @@ Gem::Specification.new do |spec|
22
22
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
23
  spec.require_paths = ["lib"]
24
24
 
25
- spec.add_dependency "sentry-ruby-core", "~> 5.3.1"
25
+ spec.add_dependency "sentry-ruby", "~> 5.16.1"
26
26
  spec.add_dependency "sidekiq", ">= 3.0"
27
27
  end
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sentry-sidekiq
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.3.1
4
+ version: 5.16.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sentry Team
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-05-14 00:00:00.000000000 Z
11
+ date: 2024-01-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: sentry-ruby-core
14
+ name: sentry-ruby
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 5.3.1
19
+ version: 5.16.1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 5.3.1
26
+ version: 5.16.1
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: sidekiq
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -49,7 +49,6 @@ files:
49
49
  - ".gitignore"
50
50
  - ".rspec"
51
51
  - CHANGELOG.md
52
- - CODE_OF_CONDUCT.md
53
52
  - Gemfile
54
53
  - LICENSE.txt
55
54
  - Makefile
@@ -62,8 +61,10 @@ files:
62
61
  - example/config/sidekiq.yml
63
62
  - example/error_worker.rb
64
63
  - lib/sentry-sidekiq.rb
64
+ - lib/sentry/sidekiq-scheduler/scheduler.rb
65
65
  - lib/sentry/sidekiq/configuration.rb
66
66
  - lib/sentry/sidekiq/context_filter.rb
67
+ - lib/sentry/sidekiq/cron/job.rb
67
68
  - lib/sentry/sidekiq/error_handler.rb
68
69
  - lib/sentry/sidekiq/sentry_context_middleware.rb
69
70
  - lib/sentry/sidekiq/version.rb
data/CODE_OF_CONDUCT.md DELETED
@@ -1,74 +0,0 @@
1
- # Contributor Covenant Code of Conduct
2
-
3
- ## Our Pledge
4
-
5
- In the interest of fostering an open and welcoming environment, we as
6
- contributors and maintainers pledge to making participation in our project and
7
- our community a harassment-free experience for everyone, regardless of age, body
8
- size, disability, ethnicity, gender identity and expression, level of experience,
9
- nationality, personal appearance, race, religion, or sexual identity and
10
- orientation.
11
-
12
- ## Our Standards
13
-
14
- Examples of behavior that contributes to creating a positive environment
15
- include:
16
-
17
- * Using welcoming and inclusive language
18
- * Being respectful of differing viewpoints and experiences
19
- * Gracefully accepting constructive criticism
20
- * Focusing on what is best for the community
21
- * Showing empathy towards other community members
22
-
23
- Examples of unacceptable behavior by participants include:
24
-
25
- * The use of sexualized language or imagery and unwelcome sexual attention or
26
- advances
27
- * Trolling, insulting/derogatory comments, and personal or political attacks
28
- * Public or private harassment
29
- * Publishing others' private information, such as a physical or electronic
30
- address, without explicit permission
31
- * Other conduct which could reasonably be considered inappropriate in a
32
- professional setting
33
-
34
- ## Our Responsibilities
35
-
36
- Project maintainers are responsible for clarifying the standards of acceptable
37
- behavior and are expected to take appropriate and fair corrective action in
38
- response to any instances of unacceptable behavior.
39
-
40
- Project maintainers have the right and responsibility to remove, edit, or
41
- reject comments, commits, code, wiki edits, issues, and other contributions
42
- that are not aligned to this Code of Conduct, or to ban temporarily or
43
- permanently any contributor for other behaviors that they deem inappropriate,
44
- threatening, offensive, or harmful.
45
-
46
- ## Scope
47
-
48
- This Code of Conduct applies both within project spaces and in public spaces
49
- when an individual is representing the project or its community. Examples of
50
- representing a project or community include using an official project e-mail
51
- address, posting via an official social media account, or acting as an appointed
52
- representative at an online or offline event. Representation of a project may be
53
- further defined and clarified by project maintainers.
54
-
55
- ## Enforcement
56
-
57
- Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
- reported by contacting the project team at stan001212@gmail.com. All
59
- complaints will be reviewed and investigated and will result in a response that
60
- is deemed necessary and appropriate to the circumstances. The project team is
61
- obligated to maintain confidentiality with regard to the reporter of an incident.
62
- Further details of specific enforcement policies may be posted separately.
63
-
64
- Project maintainers who do not follow or enforce the Code of Conduct in good
65
- faith may face temporary or permanent repercussions as determined by other
66
- members of the project's leadership.
67
-
68
- ## Attribution
69
-
70
- This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
- available at [https://contributor-covenant.org/version/1/4][version]
72
-
73
- [homepage]: https://contributor-covenant.org
74
- [version]: https://contributor-covenant.org/version/1/4/