sidekiq-amigo 1.7.0 → 1.9.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: 3cf72dfd7e1bbcc7217536a2344ce5ecdec41c0ae8769b44ec91b210b9a41d0b
4
- data.tar.gz: 19f5fd437e47f5f2dc706877289f05fd7ee0d50426d4de42ac2bbdc304f9d882
3
+ metadata.gz: 330ead7f8face652362d632c9c127aa57b298d5587d1da392769b0458d1f8915
4
+ data.tar.gz: 7c0b0b9b1658eecfd202ef294580417233421edf4233eef522b747ce9c411f52
5
5
  SHA512:
6
- metadata.gz: 970fa43283e3361af6b7caa12241ad1848426af476d0023a38148d435dbb07b7eabe31a79c2e0c23bce380097e1c5f9282eb16ef16a6e6372e6185fa1243744b
7
- data.tar.gz: 7e421c9750235136306e8ae9010101d2611c4e8cf54a0cf8192407adba26e160ec17247db045d1e6c9c85c89cc67a383379bc625f01c88f81da683ca338ce860
6
+ metadata.gz: 898c24b82de6313c33e50b58a2c4d64ca365918a0aee2b223b452fea9428cc4d265b15975ebc2f7c7e689f547898e65b7c52d3e50edbe9bcdb062f3b25f3f0b6
7
+ data.tar.gz: a5ffcb482859fcddd6727a9869bef3ed00c8edb5b1b44f0cde84b31eddb44c6f84fbac6b45d8b8fccf06c712f6792a8ce3e211b4a49083fe8c0bab76474a5d38
@@ -81,7 +81,6 @@ module Amigo
81
81
  app_id_or_app_name: ENV.fetch("HEROKU_APP_NAME"),
82
82
  formation_id_or_formation_type: "worker"
83
83
  )
84
-
85
84
  @heroku = heroku
86
85
  @max_additional_workers = max_additional_workers
87
86
  @app_id_or_app_name = app_id_or_app_name
@@ -92,6 +92,13 @@ module Amigo
92
92
  # Proc/callable called with (level, message, params={}).
93
93
  # By default, use +Amigo.log+ (which logs to the Sidekiq logger).
94
94
  attr_reader :log
95
+ # Proc called with an exception that occurs while the thread is running.
96
+ # If the handler returns +true+, then the thread will keep going.
97
+ # All other values will kill the thread, which breaks autoscaling.
98
+ # Note that Amigo automatically logs unhandled exceptions at :error level.
99
+ # If you use an error reporter like Sentry, you can pass in something like:
100
+ # -> (e) { Sentry.capture_exception(e) }
101
+ attr_reader :on_unhandled_exception
95
102
 
96
103
  def initialize(
97
104
  poll_interval: 20,
@@ -101,9 +108,9 @@ module Amigo
101
108
  alert_interval: 120,
102
109
  latency_restored_threshold: latency_threshold,
103
110
  latency_restored_handlers: [:log],
104
- log: ->(level, message, params={}) { Amigo.log(nil, level, message, params) }
111
+ log: ->(level, message, params={}) { Amigo.log(nil, level, message, params) },
112
+ on_unhandled_exception: nil
105
113
  )
106
-
107
114
  raise ArgumentError, "latency_threshold must be > 0" if
108
115
  latency_threshold <= 0
109
116
  raise ArgumentError, "latency_restored_threshold must be >= 0" if
@@ -118,8 +125,10 @@ module Amigo
118
125
  @latency_restored_threshold = latency_restored_threshold
119
126
  @latency_restored_handlers = latency_restored_handlers.freeze
120
127
  @log = log
128
+ @on_unhandled_exception = on_unhandled_exception
121
129
  end
122
130
 
131
+ # @return [Thread]
123
132
  def polling_thread
124
133
  return @polling_thread
125
134
  end
@@ -189,6 +198,14 @@ module Amigo
189
198
  end
190
199
 
191
200
  def check
201
+ self._check
202
+ rescue StandardError => e
203
+ self._log(:error, "async_autoscaler_unhandled_error", exception: e)
204
+ handled = self.on_unhandled_exception&.call(e)
205
+ raise e unless handled.eql?(true)
206
+ end
207
+
208
+ def _check
192
209
  now = Time.now
193
210
  skip_check = now < (@last_alerted + self.alert_interval)
194
211
  if skip_check
data/lib/amigo/retry.rb CHANGED
@@ -17,18 +17,29 @@ require "sidekiq/api"
17
17
  # end
18
18
  module Amigo
19
19
  module Retry
20
- class Error < StandardError; end
20
+ class Error < StandardError
21
+ protected def exc_or_msg(timing_msg, obj)
22
+ return timing_msg if obj.nil?
23
+ return obj.to_s unless obj.is_a?(Exception)
24
+ return "#{timing_msg} (#{obj.class}: #{obj.message})"
25
+ end
26
+
27
+ protected def exc?(ex)
28
+ return ex.is_a?(Exception) ? ex : nil
29
+ end
30
+ end
21
31
 
22
32
  # Raise this class, or a subclass of it, to schedule a later retry,
23
33
  # rather than using an error to trigger Sidekiq's default retry behavior.
24
34
  # The benefit here is that it allows a consistent, customizable behavior,
25
35
  # so is better for 'expected' errors like rate limiting.
26
36
  class Retry < Error
27
- attr_accessor :interval_or_timestamp
37
+ attr_accessor :interval_or_timestamp, :wrapped
28
38
 
29
39
  def initialize(interval_or_timestamp, msg=nil)
30
40
  @interval_or_timestamp = interval_or_timestamp
31
- super(msg || "retry job in #{interval_or_timestamp}")
41
+ @wrapped = exc?(msg)
42
+ super(exc_or_msg("retry job in #{interval_or_timestamp.to_i}s", msg))
32
43
  end
33
44
  end
34
45
 
@@ -37,18 +48,25 @@ module Amigo
37
48
  # This allows jobs to hard-fail when there is something like a total outage,
38
49
  # rather than retrying.
39
50
  class Die < Error
51
+ attr_accessor :wrapped
52
+
53
+ def initialize(msg=nil)
54
+ @wrapped = exc?(msg)
55
+ super(exc_or_msg("kill job", msg))
56
+ end
40
57
  end
41
58
 
42
59
  # Raise this class, or a subclass of it, to:
43
60
  # - Use +Retry+ exception semantics while the current attempt is <= +attempts+, or
44
61
  # - Use +Die+ exception semantics if the current attempt is > +attempts+.
45
62
  class OrDie < Error
46
- attr_reader :attempts, :interval_or_timestamp
63
+ attr_reader :attempts, :interval_or_timestamp, :wrapped
47
64
 
48
65
  def initialize(attempts, interval_or_timestamp, msg=nil)
66
+ @wrapped = exc?(msg)
49
67
  @attempts = attempts
50
68
  @interval_or_timestamp = interval_or_timestamp
51
- super(msg || "retry every #{interval_or_timestamp} up to #{attempts} times")
69
+ super(exc_or_msg("retry every #{interval_or_timestamp.to_i}s up to #{attempts} times", msg))
52
70
  end
53
71
  end
54
72
 
@@ -56,6 +74,12 @@ module Amigo
56
74
  # from deep in a job and they want to jump out of the whole thing.
57
75
  # Usually you should log before raising this!
58
76
  class Quit < Error
77
+ attr_accessor :wrapped
78
+
79
+ def initialize(msg=nil)
80
+ @wrapped = exc?(msg)
81
+ super(exc_or_msg("quit job", msg))
82
+ end
59
83
  end
60
84
 
61
85
  class ServerMiddleware
data/lib/amigo/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Amigo
4
- VERSION = "1.7.0"
4
+ VERSION = "1.9.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sidekiq-amigo
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.0
4
+ version: 1.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lithic Technology
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-04-12 00:00:00.000000000 Z
11
+ date: 2025-02-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sidekiq