sidekiq-failures 1.0.4 → 1.1.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.
@@ -1,49 +1,130 @@
1
1
  module Sidekiq
2
2
  module Failures
3
3
  module WebExtension
4
+ LEGACY_SIDEKIQ_VERSION = Gem::Version.new("7.3.9")
5
+
6
+ # Helper method to check Sidekiq version
7
+ def self.legacy_sidekiq?
8
+ Gem::Version.new(Sidekiq::VERSION) <= LEGACY_SIDEKIQ_VERSION
9
+ end
10
+
11
+ # Helper method to get parameters based on path and parameter name
12
+ def self.fetch_param_value(path, param_name)
13
+ if legacy_sidekiq?
14
+ # For newer Sidekiq, use route_params or url_params based on path
15
+ lambda { |env| env.params[param_name] }
16
+ else
17
+ # For legacy Sidekiq, just use params
18
+ if path.include?(":#{param_name}")
19
+ lambda { |env| env.route_params(param_name.to_sym) }
20
+ else
21
+ lambda { |env| env.url_params(param_name.to_s) }
22
+ end
23
+ end
24
+ end
25
+
26
+ # Helper method to handle parse_params vs parse_key compatibility
27
+ def self.parse_key_or_params
28
+ lambda do |env, key|
29
+ if env.respond_to?(:parse_key)
30
+ env.parse_key(key)
31
+ else
32
+ env.parse_params(key)
33
+ end
34
+ end
35
+ end
36
+
37
+ # Define the helper method implementation that will be used in both versions
38
+ # Instead of a static lambda, we'll return a method that needs to be evaluated in context
39
+ def self.safe_relative_time_implementation
40
+ lambda do |time, context|
41
+ return unless time
42
+
43
+ time = if time.is_a?(Numeric)
44
+ Time.at(time)
45
+ else
46
+ Time.parse(time)
47
+ end
48
+
49
+ # Use the context to call relative_time
50
+ context.relative_time(time)
51
+ end
52
+ end
53
+
54
+ # Define the helpers module for Sidekiq 8.0+
55
+ module FailuresHelpers
56
+ def safe_relative_time(time)
57
+ # Pass self (the context with relative_time) to the implementation
58
+ WebExtension.safe_relative_time_implementation.call(time, self)
59
+ end
60
+ end
4
61
 
5
62
  def self.registered(app)
6
63
  view_path = File.join(File.expand_path("..", __FILE__), "views")
64
+ if legacy_sidekiq?
65
+ failures_view_path = File.join(view_path, "failures_legacy.erb")
66
+ failure_view_path = File.join(view_path, "failure_legacy.erb")
67
+ else
68
+ failures_view_path = File.join(view_path, "failures.erb")
69
+ failure_view_path = File.join(view_path, "failure.erb")
70
+ end
7
71
 
8
- app.helpers do
9
- def safe_relative_time(time)
10
- time = if time.is_a?(Numeric)
11
- Time.at(time)
12
- else
13
- Time.parse(time)
14
- end
72
+ # Create a parse helper for use in routes
73
+ parse_helper = parse_key_or_params
15
74
 
16
- relative_time(time)
75
+ # Use appropriate helpers implementation based on Sidekiq version
76
+ if legacy_sidekiq?
77
+ # Original implementation for older Sidekiq versions
78
+ app.helpers do
79
+ define_method(:safe_relative_time) do |time|
80
+ # Pass self (the context with relative_time) to the implementation
81
+ WebExtension.safe_relative_time_implementation.call(time, self)
82
+ end
17
83
  end
84
+ else
85
+ # New implementation for Sidekiq 8.0+
86
+ app.helpers(FailuresHelpers)
18
87
  end
19
88
 
20
89
  app.get "/failures" do
21
- @count = (params[:count] || 25).to_i
22
- (@current_page, @total_size, @failures) = page(LIST_KEY, params[:page], @count, :reverse => true)
90
+ page_param = Sidekiq::Failures::WebExtension.fetch_param_value("/failures", "page").call(self)
91
+ count_param = Sidekiq::Failures::WebExtension.fetch_param_value("/failures", "count").call(self)
92
+ @count = (count_param || 25).to_i
93
+
94
+ (@current_page, @total_size, @failures) = page(LIST_KEY, page_param, @count, :reverse => true)
23
95
  @failures = @failures.map {|msg, score| Sidekiq::SortedEntry.new(nil, score, msg) }
24
96
 
25
- render(:erb, File.read(File.join(view_path, "failures.erb")))
97
+ render(:erb, File.read(failures_view_path))
26
98
  end
27
99
 
28
100
  app.get "/failures/:key" do
29
- halt 404 unless params['key']
30
-
31
- @failure = FailureSet.new.fetch(*parse_params(params['key'])).first
32
- redirect "#{root_path}failures" if @failure.nil?
33
- render(:erb, File.read(File.join(view_path, "failure.erb")))
101
+ key_param = Sidekiq::Failures::WebExtension.fetch_param_value("/failures/:key", "key").call(self)
102
+ halt 404 unless key_param
103
+
104
+ @failure = FailureSet.new.fetch(*parse_helper.call(self, key_param)).first
105
+ if @failure.nil?
106
+ redirect "#{root_path}failures"
107
+ else
108
+ render(:erb, File.read(failure_view_path))
109
+ end
34
110
  end
35
111
 
36
112
  app.post "/failures" do
37
- halt 404 unless params['key']
113
+ key_param = Sidekiq::Failures::WebExtension.fetch_param_value("/failures", "key").call(self)
114
+ halt 404 unless key_param
38
115
 
39
- params['key'].each do |key|
40
- job = FailureSet.new.fetch(*parse_params(key)).first
116
+ key_param.each do |key|
117
+ job = FailureSet.new.fetch(*parse_helper.call(self, key)).first
41
118
  next unless job
42
119
 
43
- if params['retry']
120
+ retry_param = Sidekiq::Failures::WebExtension.fetch_param_value("/failures", "retry").call(self)
121
+ if retry_param
44
122
  job.retry_failure
45
- elsif params['delete']
46
- job.delete
123
+ else
124
+ delete_param = Sidekiq::Failures::WebExtension.fetch_param_value("/failures", "delete").call(self)
125
+ if delete_param
126
+ job.delete
127
+ end
47
128
  end
48
129
  end
49
130
 
@@ -51,21 +132,26 @@ module Sidekiq
51
132
  end
52
133
 
53
134
  app.post "/failures/:key" do
54
- halt 404 unless params['key']
135
+ key_param = Sidekiq::Failures::WebExtension.fetch_param_value("/failures/:key", "key").call(self)
136
+ halt 404 unless key_param
55
137
 
56
- job = FailureSet.new.fetch(*parse_params(params['key'])).first
138
+ job = FailureSet.new.fetch(*parse_helper.call(self, key_param)).first
57
139
  if job
58
- if params['retry']
140
+ retry_param = Sidekiq::Failures::WebExtension.fetch_param_value("/failures/:key", "retry").call(self)
141
+ if retry_param
59
142
  job.retry_failure
60
- elsif params['delete']
61
- job.delete
143
+ else
144
+ delete_param = Sidekiq::Failures::WebExtension.fetch_param_value("/failures/:key", "delete").call(self)
145
+ if delete_param
146
+ job.delete
147
+ end
62
148
  end
63
149
  end
64
150
  redirect_with_query("#{root_path}failures")
65
151
  end
66
152
 
67
153
  app.post "/failures/all/reset" do
68
- Sidekiq::Failures.reset_failures
154
+ Sidekiq::Failures.reset_failure_count
69
155
  redirect "#{root_path}failures"
70
156
  end
71
157
 
@@ -84,10 +170,11 @@ module Sidekiq
84
170
  end
85
171
 
86
172
  app.post '/filter/failures' do
87
- @failures = Sidekiq::Failures::FailureSet.new.scan("*#{params[:substr]}*")
173
+ substr_param = Sidekiq::Failures::WebExtension.fetch_param_value("/filter/failures", "substr").call(self)
174
+ @failures = Sidekiq::Failures::FailureSet.new.scan("*#{substr_param}*")
88
175
  @current_page = 1
89
- @count = @total_size = @failures.count
90
- render(:erb, File.read(File.join(view_path, "failures.erb")))
176
+ @count = @total_size = @failures.count
177
+ render(:erb, File.read(failures_view_path))
91
178
  end
92
179
  end
93
180
  end
@@ -59,9 +59,19 @@ module Sidekiq
59
59
  LIST_KEY = :failed
60
60
 
61
61
  def self.reset_failures
62
+ warn "NOTE: Sidekiq::Failures.reset_failures is deprecated; use Sidekiq::Failures.reset_failure_count instead."
63
+
64
+ reset_failure_count
65
+ end
66
+
67
+ def self.reset_failure_count
62
68
  Sidekiq.redis { |c| c.set("stat:failed", 0) }
63
69
  end
64
70
 
71
+ def self.clear_failures
72
+ FailureSet.new.clear
73
+ end
74
+
65
75
  def self.count
66
76
  Sidekiq.redis {|r| r.zcard(LIST_KEY) }
67
77
  end
@@ -87,7 +97,14 @@ Sidekiq.configure_server do |config|
87
97
  end
88
98
 
89
99
  if defined?(Sidekiq::Web)
90
- Sidekiq::Web.register Sidekiq::Failures::WebExtension
91
- Sidekiq::Web.tabs["Failures"] = "failures"
92
- Sidekiq::Web.settings.locales << File.join(File.dirname(__FILE__), "failures/locales")
100
+ if Sidekiq::Failures::WebExtension.legacy_sidekiq?
101
+ Sidekiq::Web.register Sidekiq::Failures::WebExtension
102
+ Sidekiq::Web.tabs["Failures"] = "failures"
103
+ Sidekiq::Web.settings.locales << File.join(File.dirname(__FILE__), "failures/locales")
104
+ else
105
+ Sidekiq::Web.configure do |config|
106
+ config.locales << File.join(File.dirname(__FILE__), "failures/locales")
107
+ config.register(Sidekiq::Failures::WebExtension, name: "failures", tab: ["Failures"], index: ["failures"])
108
+ end
109
+ end
93
110
  end
@@ -28,5 +28,4 @@ Gem::Specification.new do |gem|
28
28
  gem.add_development_dependency "rack-test"
29
29
  gem.add_development_dependency "sprockets"
30
30
  gem.add_development_dependency "sinatra"
31
- gem.add_development_dependency "pry"
32
31
  end
@@ -3,7 +3,7 @@ require "test_helper"
3
3
  module Sidekiq
4
4
  describe Failures do
5
5
  describe '.retry_middleware_class' do
6
- it 'returns based on Sidekiq::VERISON' do
6
+ it 'returns based on Sidekiq::VERSION' do
7
7
  case Sidekiq::VERSION[0]
8
8
  when '5'
9
9
  assert_equal Failures.retry_middleware_class, Sidekiq::JobRetry
@@ -29,20 +29,29 @@ end
29
29
 
30
30
  class SidekiqPost63
31
31
  def new_processor(boss)
32
- config = Sidekiq
32
+ config = ::Sidekiq
33
33
  config[:queues] = ['default']
34
- config[:fetch] = Sidekiq::BasicFetch.new(config)
34
+ config[:fetch] = ::Sidekiq::BasicFetch.new(config)
35
35
  config[:error_handlers] << Sidekiq.method(:default_error_handler)
36
36
  ::Sidekiq::Processor.new(config) { |processor, reason = nil| }
37
37
  end
38
38
  end
39
39
 
40
+ class SidekiqPost7
41
+ def new_processor(boss)
42
+ config = ::Sidekiq.default_configuration
43
+ ::Sidekiq::Processor.new(config.default_capsule) { |*args| }
44
+ end
45
+ end
46
+
40
47
  module Sidekiq
41
48
  module Failures
42
49
  describe "Middleware" do
43
50
  def new_provider
44
51
  version = Gem::Version.new(Sidekiq::VERSION)
45
- if version >= Gem::Version.new('6.4.0')
52
+ if version >= Gem::Version.new('7')
53
+ SidekiqPost7
54
+ elsif version >= Gem::Version.new('6.4.0')
46
55
  SidekiqPost63
47
56
  elsif version >= Gem::Version.new('6.0')
48
57
  SidekiqPre63
@@ -53,13 +62,16 @@ module Sidekiq
53
62
 
54
63
  before do
55
64
  $invokes = 0
56
- @boss = MiniTest::Mock.new
65
+ @boss = Minitest::Mock.new
57
66
  @provider = new_provider
58
67
  @processor = @provider.new_processor(@boss)
59
68
 
60
- Sidekiq.server_middleware {|chain| chain.add Sidekiq::Failures::Middleware }
61
- Sidekiq.redis = REDIS
62
- Sidekiq.redis { |c| c.flushdb }
69
+ Sidekiq.configure_server do |config|
70
+ config.server_middleware do |chain|
71
+ chain.add Sidekiq::Failures::Middleware
72
+ end
73
+ end
74
+ Sidekiq.redis(&:flushdb)
63
75
  Sidekiq.instance_eval { @failures_default_mode = nil }
64
76
  end
65
77
 
@@ -96,7 +108,7 @@ module Sidekiq
96
108
  assert_equal 0, failures_count
97
109
 
98
110
  assert_raises TestException do
99
- @processor.process(msg)
111
+ @processor.send(:process, msg)
100
112
  end
101
113
 
102
114
  assert_equal 1, failures_count
@@ -109,7 +121,7 @@ module Sidekiq
109
121
  assert_equal 0, failures_count
110
122
 
111
123
  assert_raises TestException do
112
- @processor.process(msg)
124
+ @processor.send(:process, msg)
113
125
  end
114
126
 
115
127
  assert_equal 1, failures_count
@@ -121,7 +133,7 @@ module Sidekiq
121
133
 
122
134
  assert_equal 0, failures_count
123
135
 
124
- @processor.process(msg)
136
+ @processor.send(:process, msg)
125
137
 
126
138
  assert_equal 0, failures_count
127
139
  assert_equal 1, $invokes
@@ -133,7 +145,7 @@ module Sidekiq
133
145
  assert_equal 0, failures_count
134
146
 
135
147
  assert_raises TestException do
136
- @processor.process(msg)
148
+ @processor.send(:process, msg)
137
149
  end
138
150
 
139
151
  assert_equal 0, failures_count
@@ -148,21 +160,20 @@ module Sidekiq
148
160
  assert_equal 0, failures_count
149
161
 
150
162
  assert_raises TestException do
151
- @processor.process(msg)
163
+ @processor.send(:process, msg)
152
164
  end
153
165
 
154
166
  assert_equal 0, failures_count
155
167
  assert_equal 1, $invokes
156
168
  end
157
169
 
158
-
159
170
  it "doesn't record failure if going to be retired again and configured to track exhaustion" do
160
171
  msg = create_work('class' => MockWorker.to_s, 'args' => ['myarg'], 'retry' => true, 'failures' => 'exhausted')
161
172
 
162
173
  assert_equal 0, failures_count
163
174
 
164
175
  assert_raises TestException do
165
- @processor.process(msg)
176
+ @processor.send(:process, msg)
166
177
  end
167
178
 
168
179
  assert_equal 0, failures_count
@@ -175,7 +186,7 @@ module Sidekiq
175
186
  assert_equal 0, failures_count
176
187
 
177
188
  assert_raises TestException do
178
- @processor.process(msg)
189
+ @processor.send(:process, msg)
179
190
  end
180
191
 
181
192
  assert_equal 1, failures_count
@@ -188,7 +199,7 @@ module Sidekiq
188
199
  assert_equal 0, failures_count
189
200
 
190
201
  assert_raises TestException do
191
- @processor.process(msg)
202
+ @processor.send(:process, msg)
192
203
  end
193
204
 
194
205
  assert_equal 1, failures_count
@@ -203,7 +214,7 @@ module Sidekiq
203
214
  assert_equal 0, failures_count
204
215
 
205
216
  assert_raises TestException do
206
- @processor.process(msg)
217
+ @processor.send(:process, msg)
207
218
  end
208
219
 
209
220
  assert_equal 1, failures_count
@@ -218,7 +229,7 @@ module Sidekiq
218
229
  assert_equal 0, failures_count
219
230
 
220
231
  assert_raises TestException do
221
- @processor.process(msg)
232
+ @processor.send(:process, msg)
222
233
  end
223
234
 
224
235
  assert_equal 1, failures_count
@@ -234,11 +245,11 @@ module Sidekiq
234
245
  assert_equal 0, failures_count
235
246
 
236
247
  3.times do
237
- boss = MiniTest::Mock.new
248
+ boss = Minitest::Mock.new
238
249
  processor = @provider.new_processor(boss)
239
250
 
240
251
  assert_raises TestException do
241
- processor.process(msg)
252
+ processor.send(:process, msg)
242
253
  end
243
254
 
244
255
  boss.verify
@@ -259,7 +270,7 @@ module Sidekiq
259
270
  assert_equal 0, Sidekiq::Failures.count
260
271
 
261
272
  assert_raises TestException do
262
- @processor.process(msg)
273
+ @processor.send(:process, msg)
263
274
  end
264
275
 
265
276
  assert_equal 1, Sidekiq::Failures.count
data/test/test_helper.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  $TESTING = true
2
2
 
3
+ ENV["MT_CPU"] = "1" # Disable parallel testing to avoid flaky tests, force a single CPU for minitest
4
+
3
5
  require "minitest/autorun"
4
6
  require "minitest/spec"
5
7
  require "minitest/mock"
@@ -15,4 +17,4 @@ require "sidekiq/cli"
15
17
 
16
18
  Sidekiq.logger.level = Logger::ERROR
17
19
 
18
- REDIS = Sidekiq::RedisConnection.create(url: "redis://localhost/15")
20
+ REDIS = Sidekiq::RedisConnection.create(url: "redis://127.0.0.1:6379/15") # Use DB 15 for testing