sidekiq-rescue 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dd1cc37dddad565e32a86226f22111be381fffb62f80253e36dbd563598531be
4
- data.tar.gz: 050f58d316e722f243b7eb49a5396cb56aa0ba368d827099aa4ca2dafafe43a0
3
+ metadata.gz: f7e9209b0b3fcb19ae0068540e6a83aedf56928457fd53584e6ebf7397ef541a
4
+ data.tar.gz: debef2495e57e1452f19982777fb2238f75c811ab48a161f36858beff7f7a7e1
5
5
  SHA512:
6
- metadata.gz: 34d0325a6547e9ff4087114fb20c424383a62a144bafe72ede1ed53badecdba38affa32f6b695a5e68ab02c100c96629dfce30bc766f656f5dc319659e8e9489
7
- data.tar.gz: a6d66d595d8e75e18cadb0f4e7360e49604c36a86c2587b249cb3e98fb4d90b30564ecf1e88d574c97ec34e5673e7a6df12b4d36d45eede6f6529cab9c1423c5
6
+ metadata.gz: 96620e97aeabdfb9bc0ed8df29216e5017409c28e126e0e41d3941b3dde8548b5a4ecf0c1e54253f6280a8046291f21e2110ab3c514673f26cb1a557b895f754
7
+ data.tar.gz: a01212d26bdfb69c4dd3377a89fdeae379f8a016d8e98087b5c916528e0a54191bdff9b99d5e41330e81b7d971aea0da18fcde7058d1f727d525ac57e29d72b6
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.6.0] - 2025-03-15
4
+ - Add support for Sidekiq 8.0, Ruby 3.4 [#6](https://github.com/moofkit/sidekiq-rescue/pull/6)
5
+
6
+ ## [0.5.0] - 2024-10-17
7
+ - Add support for queue configuration [#5](https://github.com/moofkit/sidekiq-rescue/pull/5)
8
+
3
9
  ## [0.4.0] - 2024-06-03
4
10
  - Add support for jitter configuration [#4](https://github.com/moofkit/sidekiq-rescue/pull/4)
5
11
  - Changes the strategy for retry delay. Now it's calculated using the formula `delay + delay * jitter * rand`
@@ -34,7 +40,9 @@
34
40
  - Add documentation
35
41
  - Add CI
36
42
 
37
- [Unreleased]: https://github.com/moofkit/sidekiq-rescue/compare/v0.4.0...HEAD
43
+ [Unreleased]: https://github.com/moofkit/sidekiq-rescue/compare/v0.6.0...HEAD
44
+ [0.6.0]: https://github.com/moofkit/sidekiq-rescue/releases/tag/v0.6.0
45
+ [0.5.0]: https://github.com/moofkit/sidekiq-rescue/releases/tag/v0.5.0
38
46
  [0.4.0]: https://github.com/moofkit/sidekiq-rescue/releases/tag/v0.4.0
39
47
  [0.3.1]: https://github.com/moofkit/sidekiq-rescue/releases/tag/v0.3.1
40
48
  [0.3.0]: https://github.com/moofkit/sidekiq-rescue/releases/tag/v0.3.0
data/README.md CHANGED
@@ -16,14 +16,16 @@ class MyJob
16
16
 
17
17
  sidekiq_rescue CustomAppException # defaults to 60 seconds delay and 10 retries
18
18
  sidekiq_rescue AnotherCustomAppException, delay: ->(counter) { counter * 2 }
19
- sidekiq_rescue CustomInfrastructureException, delay: 5.minutes
20
- sidekiq_rescue ActiveRecord::Deadlocked, delay: 5.seconds, limit: 3
19
+ sidekiq_rescue CustomInfrastructureException, delay: 5.minutes.to_i
20
+ sidekiq_rescue ActiveRecord::Deadlocked, delay: 5.seconds.to_i, limit: 3
21
+ sidekiq_rescue TooManyRequestsError, queue: "slow"
21
22
  sidekiq_rescue Net::OpenTimeout, Timeout::Error, limit: 10 # retries at most 10 times for Net::OpenTimeout and Timeout::Error combined
22
23
 
23
24
  def perform(*args)
24
25
  # Might raise CustomAppException, AnotherCustomAppException, or YetAnotherCustomAppException for something domain specific
25
26
  # Might raise ActiveRecord::Deadlocked when a local db deadlock is detected
26
27
  # Might raise Net::OpenTimeout or Timeout::Error when the remote service is down
28
+ # Might raise TooManyRequestsError when the rate limit is exceeded
27
29
  end
28
30
  end
29
31
  ```
@@ -74,7 +76,7 @@ end
74
76
 
75
77
  ## Configuration
76
78
 
77
- You can configure the number of retries and the delay (in seconds) between retries:
79
+ You can configure the number of retries and the delay *in seconds* between retries:
78
80
 
79
81
  ```ruby
80
82
  class MyJob
@@ -89,7 +91,12 @@ class MyJob
89
91
  end
90
92
  ```
91
93
 
92
- The `delay` is not the exact time between retries, but a minimum delay. The actual delay calculates based on jitter and `delay` value. The formula is `delay + delay * jitter * rand` seconds. Randomization is used to avoid retry storms. The `jitter` represents the upper bound of possible wait time (expressed as a percentage) and defaults to 0.15 (15%).
94
+ * `delay` - the delay between retries in seconds
95
+ * `limit` - the number of retries. The number of attempts includes the original job execution.
96
+ * `jitter` - represents the upper bound of possible wait time (expressed as a percentage) and defaults to 0.15 (15%)
97
+ * `queue` - the queue to which the job will be enqueued if it fails
98
+
99
+ The `delay` is not the exact time between retries, but a minimum delay. The actual delay calculates based on jitter and `delay` value. The formula is `delay + delay * jitter * rand` seconds. Randomization is used to avoid retry storms.
93
100
 
94
101
  The default values are:
95
102
  - `delay`: 60 seconds
@@ -261,7 +268,7 @@ If something doesn't work on one of these versions, it's a bug
261
268
 
262
269
  ## Supported Sidekiq versions
263
270
 
264
- This gem supports Sidekiq 6.5+. It may work with older versions, but it's not tested.
271
+ This gem supports Sidekiq 7.0+. It may work with older versions, but it's not tested.
265
272
 
266
273
  If you need support for older versions, please open an issue
267
274
 
@@ -23,15 +23,19 @@ module Sidekiq
23
23
  # @raise [ArgumentError] if delay is not an Integer or Float
24
24
  # @raise [ArgumentError] if limit is not an Integer
25
25
  # @raise [ArgumentError] if jitter is not an Integer or Float
26
+ # @raise [ArgumentError] if queue is not a String
26
27
  # @example
27
28
  # sidekiq_rescue NetworkError, delay: 60, limit: 10
28
29
  def sidekiq_rescue(*errors, delay: Sidekiq::Rescue.config.delay, limit: Sidekiq::Rescue.config.limit,
29
- jitter: Sidekiq::Rescue.config.jitter)
30
+ jitter: Sidekiq::Rescue.config.jitter, queue: nil)
30
31
  unpacked_errors = validate_and_unpack_error_argument(errors)
31
32
  validate_delay_argument(delay)
32
33
  validate_limit_argument(limit)
33
34
  validate_jitter_argument(jitter)
34
- assign_sidekiq_rescue_options(errors: unpacked_errors, delay: delay, limit: limit, jitter: jitter)
35
+ validate_queue_argument(queue)
36
+ assign_sidekiq_rescue_options(
37
+ errors: unpacked_errors, delay:, limit:, jitter:, queue:
38
+ )
35
39
  end
36
40
 
37
41
  # Find the error group and options for the given exception.
@@ -77,10 +81,18 @@ module Sidekiq
77
81
  "jitter must be integer or float"
78
82
  end
79
83
 
80
- def assign_sidekiq_rescue_options(errors:, delay:, limit:, jitter:)
84
+ def validate_queue_argument(queue)
85
+ return if queue.nil? || queue.is_a?(String)
86
+
87
+ raise ArgumentError,
88
+ "queue must be a string"
89
+ end
90
+
91
+ def assign_sidekiq_rescue_options(errors:, delay:, limit:, jitter:, queue:)
81
92
  self.sidekiq_rescue_options ||= {}
82
- self.sidekiq_rescue_options = self.sidekiq_rescue_options.merge(errors => { delay: delay, limit: limit,
83
- jitter: jitter })
93
+ self.sidekiq_rescue_options = self.sidekiq_rescue_options.merge(errors => {
94
+ delay:, limit:, jitter:, queue:
95
+ }.compact)
84
96
  end
85
97
  end
86
98
  end
@@ -15,6 +15,8 @@ module Sidekiq
15
15
  str = "expected #{actual} to be rescueable with #{expected}"
16
16
  str += " and delay #{@delay}" if @delay
17
17
  str += " and limit #{@limit}" if @limit
18
+ str += " and jitter #{@jitter}" if @jitter
19
+ str += " and queue #{@queue}" if @queue
18
20
  str
19
21
  end
20
22
  failure_message_when_negated { |actual| "expected #{actual} not to be rescueable with #{expected}" }
@@ -27,23 +29,36 @@ module Sidekiq
27
29
  @limit = limit
28
30
  end
29
31
 
32
+ chain :with_jitter do |jitter|
33
+ @jitter = jitter
34
+ end
35
+
36
+ chain :with_queue do |queue|
37
+ @queue = queue
38
+ end
39
+
30
40
  match do |actual|
31
41
  matched = actual.is_a?(Class) &&
32
42
  actual.include?(Sidekiq::Rescue::Dsl) &&
33
43
  actual.respond_to?(:sidekiq_rescue_options) &&
34
- actual&.sidekiq_rescue_options&.keys&.flatten&.include?(expected)
44
+ actual.sidekiq_rescue_options.is_a?(Hash) &&
45
+ actual.sidekiq_rescue_options.keys.flatten.include?(expected)
35
46
 
36
47
  return false unless matched
37
48
 
38
49
  _error_group, options = actual.sidekiq_rescue_error_group_with_options_by(expected.new)
39
50
 
40
51
  (@delay.nil? || options.fetch(:delay) == @delay) &&
41
- (@limit.nil? || options.fetch(:limit) == @limit)
52
+ (@limit.nil? || options.fetch(:limit) == @limit) &&
53
+ (@jitter.nil? || options.fetch(:jitter) == @jitter) &&
54
+ (@queue.nil? || options.fetch(:queue) == @queue)
42
55
  end
43
56
 
44
57
  match_when_negated do |actual|
45
58
  raise NotImplementedError, "it's confusing to use `not_to be_rescueable` with `with_delay`" if @delay
46
59
  raise NotImplementedError, "it's confusing to use `not_to be_rescueable` with `with_limit`" if @limit
60
+ raise NotImplementedError, "it's confusing to use `not_to be_rescueable` with `with_jitter`" if @jitter
61
+ raise NotImplementedError, "it's confusing to use `not_to be_rescueable` with `with_queue`" if @queue
47
62
 
48
63
  actual.is_a?(Class) &&
49
64
  actual.include?(Sidekiq::Rescue::Dsl) &&
@@ -9,10 +9,10 @@ module Sidekiq
9
9
  class ServerMiddleware
10
10
  include Sidekiq::ServerMiddleware
11
11
 
12
- def call(job_instance, job_payload, _queue, &block)
12
+ def call(job_instance, job_payload, _queue, &)
13
13
  job_class = job_instance.class
14
14
  if job_class.respond_to?(:sidekiq_rescue_options) && !job_class.sidekiq_rescue_options.nil?
15
- sidekiq_rescue(job_payload, job_class, &block)
15
+ sidekiq_rescue(job_payload, job_class, &)
16
16
  else
17
17
  yield
18
18
  end
@@ -31,13 +31,15 @@ module Sidekiq
31
31
 
32
32
  def rescue_error(error, error_group, options, job_payload)
33
33
  delay, limit, jitter = options.fetch_values(:delay, :limit, :jitter)
34
+ queue = options.fetch(:queue, job_payload["queue"])
35
+
34
36
  rescue_counter = increment_rescue_counter_for(error_group, job_payload)
35
37
  raise error if rescue_counter > limit
36
38
 
37
39
  calculated_delay = calculate_delay(delay, rescue_counter, jitter)
38
40
  log_reschedule_info(rescue_counter, error, calculated_delay)
39
- reschedule_job(job_payload: job_payload, delay: calculated_delay, rescue_counter: rescue_counter,
40
- error_group: error_group)
41
+ reschedule_job(job_payload:, delay: calculated_delay, rescue_counter:,
42
+ error_group:, queue:)
41
43
  end
42
44
 
43
45
  def increment_rescue_counter_for(error_group, job_payload)
@@ -63,10 +65,11 @@ module Sidekiq
63
65
  "#{error.message}; rescheduling in #{delay} seconds")
64
66
  end
65
67
 
66
- def reschedule_job(job_payload:, delay:, rescue_counter:, error_group:)
68
+ def reschedule_job(job_payload:, delay:, rescue_counter:, error_group:, queue:)
67
69
  payload = job_payload.dup
68
70
  payload["at"] = Time.now.to_f + delay if delay.positive?
69
71
  payload["sidekiq_rescue_exceptions_counter"] = { error_group.to_s => rescue_counter }
72
+ payload["queue"] = queue
70
73
  Sidekiq::Client.push(payload)
71
74
  end
72
75
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Sidekiq
4
4
  module Rescue
5
- VERSION = "0.4.0"
5
+ VERSION = "0.6.0"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sidekiq-rescue
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dmitrii Ivliev
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-06-03 00:00:00.000000000 Z
10
+ date: 2025-03-15 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: sidekiq
@@ -16,15 +15,14 @@ dependencies:
16
15
  requirements:
17
16
  - - ">="
18
17
  - !ruby/object:Gem::Version
19
- version: '6.5'
18
+ version: '7.0'
20
19
  type: :runtime
21
20
  prerelease: false
22
21
  version_requirements: !ruby/object:Gem::Requirement
23
22
  requirements:
24
23
  - - ">="
25
24
  - !ruby/object:Gem::Version
26
- version: '6.5'
27
- description:
25
+ version: '7.0'
28
26
  email:
29
27
  - mail@ivda.dev
30
28
  executables: []
@@ -50,9 +48,8 @@ metadata:
50
48
  homepage_uri: https://github.com/moofkit/sidekiq-rescue
51
49
  source_code_uri: https://github.com/moofkit/sidekiq-rescue
52
50
  changelog_uri: https://github.com/moofkit/sidekiq-rescue/blob/master/CHANGELOG.md
53
- documentation_uri: https://rubydoc.info/gems/sidekiq-rescue/0.4.0
51
+ documentation_uri: https://rubydoc.info/gems/sidekiq-rescue/0.6.0
54
52
  rubygems_mfa_required: 'true'
55
- post_install_message:
56
53
  rdoc_options: []
57
54
  require_paths:
58
55
  - lib
@@ -60,15 +57,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
60
57
  requirements:
61
58
  - - ">="
62
59
  - !ruby/object:Gem::Version
63
- version: 2.7.0
60
+ version: 3.2.0
64
61
  required_rubygems_version: !ruby/object:Gem::Requirement
65
62
  requirements:
66
63
  - - ">="
67
64
  - !ruby/object:Gem::Version
68
65
  version: '0'
69
66
  requirements: []
70
- rubygems_version: 3.5.9
71
- signing_key:
67
+ rubygems_version: 3.6.2
72
68
  specification_version: 4
73
69
  summary: Rescue Sidekiq jobs on expected error and reschedule them
74
70
  test_files: []