sidekiq-killswitch 1.1.0 → 1.1.1

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: 19e742c53121e79d47f431622fb85caaa363db4e588465fcebbef34fd24b4c66
4
- data.tar.gz: '073755898e20e6190cc4578b1094b42a8880a09e7c7825be55a27ad9ff585165'
3
+ metadata.gz: d2c1e5555f67df5c51420ca3946edcf8786c622f7ee6d7c2ef238a3c2e42f639
4
+ data.tar.gz: 5607f5785571de88fae01a9abca4637bbeb35a2418db9cda87a29f0c6f5a1bcf
5
5
  SHA512:
6
- metadata.gz: bb06743e6f30e348cf7187ac93853edde5a26c06764f52b2fd273cf6635456582d093da42632a1129dc218adf078068e6fb504441b059a46de818bdc726bbc5b
7
- data.tar.gz: 071ba3570e2ded8313c637b39442e92f2c5d781751d49efc294057c2e272b73a2136dc017e810fccb99744c29f5cf18a73a29c485aad7a27cd94eae0c8b19b12
6
+ metadata.gz: 21e69f7d202a0c5f186d4f317bcb05ec8031522bd24c05bc7720be745e12f11280a5fd1f0902cf431dce750a63c9167409b36c5d4e92b9957fe916031f3a9699
7
+ data.tar.gz: 4399541da941edfef9a83eb555e80c1c5e98ffcb76160eaf487a06bc5415af4bcb4b5c4d0dcd299ad68d292509538f2b387b80a230fac56389b0431f0e3f1b31
data/CHANGES.md CHANGED
@@ -1,3 +1,9 @@
1
+ ### 1.1.1 / 2024-08-27
2
+ * Support for `redis-client` client (used by Sidekiq 7)
3
+ * Remove `Sidekiq::DeadSet#kill` extension.
4
+ * `module Sidekiq::Killswitch; end` replaced with `module Sidekiq; module Killswitch; ...`.
5
+ * We're now using `warn` instead of `info` to log worker blackholed/dead_queued messaged.
6
+
1
7
  ### 1.1.0 / 2024-07-01
2
8
  * Add in warning banner to Sidekiq UI so users are linked to docs and informed of the difference of sending jobs to blackhole vs. dead queue
3
9
 
data/Gemfile CHANGED
@@ -2,3 +2,5 @@
2
2
  source 'http://rubygems.org'
3
3
 
4
4
  gemspec
5
+
6
+ gem 'pry-byebug'
@@ -1,36 +1,38 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Sidekiq::Killswitch
4
- class Config
5
- attr_accessor :web_ui_worker_validator
6
- attr_writer :logger
3
+ module Sidekiq
4
+ module Killswitch
5
+ class Config
6
+ attr_accessor :web_ui_worker_validator
7
+ attr_writer :logger
7
8
 
8
- def initialize
9
- self.web_ui_worker_validator = ->(worker_name) { !worker_name.nil? && worker_name != '' }
10
- end
9
+ def initialize
10
+ self.web_ui_worker_validator = ->(worker_name) { !worker_name.nil? && worker_name != '' }
11
+ end
11
12
 
12
- def logger
13
- @logger ||= Sidekiq.logger
14
- end
13
+ def logger
14
+ @logger ||= Sidekiq.logger
15
+ end
15
16
 
16
- def validate_worker_class_in_web
17
- self.web_ui_worker_validator = proc do |worker_name|
18
- begin
19
- constantize(worker_name).include?(Sidekiq::Worker)
20
- rescue NameError
21
- false
17
+ def validate_worker_class_in_web
18
+ self.web_ui_worker_validator = proc do |worker_name|
19
+ begin
20
+ constantize(worker_name).include?(Sidekiq::Worker)
21
+ rescue NameError
22
+ false
23
+ end
22
24
  end
23
25
  end
24
- end
25
26
 
26
- private
27
+ private
27
28
 
28
- def constantize(str)
29
- names = str.split('::')
30
- names.shift if names.empty? || names.first.empty?
29
+ def constantize(str)
30
+ names = str.split('::')
31
+ names.shift if names.empty? || names.first.empty?
31
32
 
32
- names.inject(Object) do |constant, name|
33
- constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
33
+ names.inject(Object) do |constant, name|
34
+ constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
35
+ end
34
36
  end
35
37
  end
36
38
  end
@@ -8,7 +8,7 @@ module Sidekiq
8
8
  worker_name = Sidekiq::Killswitch.class_to_str(worker_class)
9
9
 
10
10
  if Killswitch.blackhole_worker?(worker_name)
11
- Killswitch.logger.info "#{worker_name} is currently disabled. Job #{job} was not executed."
11
+ Killswitch.logger.warn "#{worker_name} is currently disabled. Job #{job} was not executed."
12
12
  false
13
13
  else
14
14
  yield
@@ -4,14 +4,16 @@ module Sidekiq
4
4
  module Killswitch
5
5
  module Middleware
6
6
  class Server
7
+ include Sidekiq::ServerMiddleware
8
+
7
9
  def call(worker, job, _queue)
8
10
  serialized_job = Sidekiq.dump_json(job)
9
11
 
10
12
  if Killswitch.dead_queue_worker?(worker.class)
11
13
  DeadSet.new.kill(serialized_job)
12
- Killswitch.logger.info "#{worker.class.name} marked as dead queue worker. Job #{serialized_job} was killed."
14
+ Killswitch.logger.warn "#{worker.class.name} marked as dead queue worker. Job #{serialized_job} was killed."
13
15
  elsif Killswitch.blackhole_worker?(worker.class)
14
- Killswitch.logger.info "#{worker.class.name} is currently disabled. Job #{serialized_job} was not executed."
16
+ Killswitch.logger.warn "#{worker.class.name} is currently disabled. Job #{serialized_job} was not executed."
15
17
  else
16
18
  yield
17
19
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Sidekiq
4
4
  module Killswitch
5
- VERSION = '1.1.0'
5
+ VERSION = '1.1.1'
6
6
  end
7
7
  end
@@ -1,92 +1,100 @@
1
1
  # frozen_string_literal: true
2
- require 'sidekiq/extensions/dead_set'
3
2
  require 'sidekiq/killswitch/config'
4
3
  require 'sidekiq/killswitch/middleware/server'
5
4
  require 'sidekiq/killswitch/middleware/client'
6
5
 
7
- module Sidekiq::Killswitch
8
- BLACKHOLE_WORKERS_KEY_NAME = 'sidekiq.disabled-workers'
9
- DEAD_QUEUE_WORKERS_KEY_NAME = 'sidekiq.dead-queue-workers'
6
+ module Sidekiq
7
+ module Killswitch
8
+ BLACKHOLE_WORKERS_KEY_NAME = 'sidekiq.disabled-workers'
9
+ DEAD_QUEUE_WORKERS_KEY_NAME = 'sidekiq.dead-queue-workers'
10
10
 
11
- class << self
12
- def config
13
- @config ||= Config.new
14
- end
11
+ class << self
12
+ def config
13
+ @config ||= Config.new
14
+ end
15
15
 
16
- def configure(&block)
17
- yield config
18
- end
16
+ def configure(&block)
17
+ yield config
18
+ end
19
19
 
20
- def logger
21
- config.logger
22
- end
20
+ def logger
21
+ config.logger
22
+ end
23
23
 
24
- def redis_pool(&block)
25
- Sidekiq.redis(&block)
26
- end
24
+ def redis_pool(&block)
25
+ Sidekiq.redis(&block)
26
+ end
27
27
 
28
- def blackhole_add_worker(worker_name)
29
- worker_name = class_to_str(worker_name)
28
+ def blackhole_add_worker(worker_name)
29
+ worker_name = class_to_str(worker_name)
30
30
 
31
- redis_pool do |redis|
32
- redis.hset(BLACKHOLE_WORKERS_KEY_NAME, worker_name, Time.now)
31
+ redis_pool do |redis|
32
+ redis.hset(BLACKHOLE_WORKERS_KEY_NAME, worker_name, Time.now.to_s)
33
+ end
34
+ logger.warn "#{worker_name} added to blackhole workers"
33
35
  end
34
- logger.warn "#{worker_name} added to blackhole workers"
35
- end
36
36
 
37
- def blackhole_remove_worker(worker_name)
38
- worker_name = class_to_str(worker_name)
37
+ def blackhole_remove_worker(worker_name)
38
+ worker_name = class_to_str(worker_name)
39
39
 
40
- redis_pool do |redis|
41
- redis.hdel(BLACKHOLE_WORKERS_KEY_NAME, worker_name)
40
+ redis_pool do |redis|
41
+ redis.hdel(BLACKHOLE_WORKERS_KEY_NAME, worker_name)
42
+ end
43
+ logger.warn "#{worker_name} removed from blackhole workers"
42
44
  end
43
- logger.warn "#{worker_name} removed from blackhole workers"
44
- end
45
45
 
46
- def blackhole_worker?(worker_name)
47
- redis_pool do |redis|
48
- redis.hexists(BLACKHOLE_WORKERS_KEY_NAME, class_to_str(worker_name))
46
+ def blackhole_worker?(worker_name)
47
+ redis_pool do |redis|
48
+ is_true_compat(redis.hexists(BLACKHOLE_WORKERS_KEY_NAME, class_to_str(worker_name)))
49
+ end
49
50
  end
50
- end
51
51
 
52
- def blackhole_workers
53
- redis_pool do |redis|
54
- redis.hgetall(BLACKHOLE_WORKERS_KEY_NAME)
52
+ def blackhole_workers
53
+ redis_pool do |redis|
54
+ redis.hgetall(BLACKHOLE_WORKERS_KEY_NAME)
55
+ end
55
56
  end
56
- end
57
57
 
58
- def dead_queue_add_worker(worker_name)
59
- worker_name = class_to_str(worker_name)
58
+ def dead_queue_add_worker(worker_name)
59
+ worker_name = class_to_str(worker_name)
60
60
 
61
- redis_pool do |redis|
62
- redis.hset(DEAD_QUEUE_WORKERS_KEY_NAME, worker_name, Time.now)
61
+ redis_pool do |redis|
62
+ redis.hset(DEAD_QUEUE_WORKERS_KEY_NAME, worker_name, Time.now.to_s)
63
+ end
64
+ logger.warn "#{worker_name} added to dead queue workers"
63
65
  end
64
- logger.warn "#{worker_name} added to dead queue workers"
65
- end
66
66
 
67
- def dead_queue_remove_worker(worker_name)
68
- worker_name = class_to_str(worker_name)
67
+ def dead_queue_remove_worker(worker_name)
68
+ worker_name = class_to_str(worker_name)
69
69
 
70
- redis_pool do |redis|
71
- redis.hdel(DEAD_QUEUE_WORKERS_KEY_NAME, worker_name)
70
+ redis_pool do |redis|
71
+ redis.hdel(DEAD_QUEUE_WORKERS_KEY_NAME, worker_name)
72
+ end
73
+ logger.warn "#{worker_name} removed from dead queue workers"
72
74
  end
73
- logger.warn "#{worker_name} removed from dead queue workers"
74
- end
75
75
 
76
- def dead_queue_worker?(worker_name)
77
- redis_pool do |redis|
78
- redis.hexists(DEAD_QUEUE_WORKERS_KEY_NAME, class_to_str(worker_name))
76
+ def dead_queue_worker?(worker_name)
77
+ redis_pool do |redis|
78
+ is_true_compat(redis.hexists(DEAD_QUEUE_WORKERS_KEY_NAME, class_to_str(worker_name)))
79
+ end
79
80
  end
80
- end
81
81
 
82
- def dead_queue_workers
83
- redis_pool do |redis|
84
- redis.hgetall(DEAD_QUEUE_WORKERS_KEY_NAME)
82
+ def dead_queue_workers
83
+ redis_pool do |redis|
84
+ redis.hgetall(DEAD_QUEUE_WORKERS_KEY_NAME)
85
+ end
86
+ end
87
+
88
+ def class_to_str(class_or_string)
89
+ class_or_string.is_a?(String) ? class_or_string : class_or_string.name
85
90
  end
86
- end
87
91
 
88
- def class_to_str(class_or_string)
89
- class_or_string.is_a?(String) ? class_or_string : class_or_string.name
92
+ private
93
+
94
+ def is_true_compat(redis_result_value)
95
+ # Compatibility method for `redis` and `redis-client`.
96
+ redis_result_value == 1 || redis_result_value == true
97
+ end
90
98
  end
91
99
  end
92
100
  end
@@ -65,7 +65,7 @@ RSpec.describe Sidekiq::Killswitch do
65
65
  Sidekiq::Killswitch.blackhole_remove_worker(worker_name)
66
66
 
67
67
  Sidekiq::Killswitch.redis_pool do |redis|
68
- expect(redis.hexists(Sidekiq::Killswitch::BLACKHOLE_WORKERS_KEY_NAME, worker_name)).to be_falsey
68
+ expect(redis.hexists(Sidekiq::Killswitch::BLACKHOLE_WORKERS_KEY_NAME, worker_name)).to eq(0)
69
69
  end
70
70
  end
71
71
  end
@@ -113,7 +113,7 @@ RSpec.describe Sidekiq::Killswitch do
113
113
  Sidekiq::Killswitch.dead_queue_remove_worker(worker_name)
114
114
 
115
115
  Sidekiq::Killswitch.redis_pool do |redis|
116
- expect(redis.hexists(Sidekiq::Killswitch::DEAD_QUEUE_WORKERS_KEY_NAME, worker_name)).to be_falsey
116
+ expect(redis.hexists(Sidekiq::Killswitch::DEAD_QUEUE_WORKERS_KEY_NAME, worker_name)).to eq(0)
117
117
  end
118
118
  end
119
119
  end
data/spec/spec_helper.rb CHANGED
@@ -1,10 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
  require 'rspec'
3
3
  require 'logger'
4
+ require 'rack/test'
4
5
  require 'sidekiq/testing'
5
6
  require 'sidekiq/killswitch'
6
7
 
7
8
  ENV['RACK_ENV'] = 'test' # Disable CSRF protection for Sidekiq Web app
9
+ $TESTING = true
8
10
 
9
11
  Sidekiq::Killswitch.configure do |config|
10
12
  config.logger = Logger.new('/dev/null')
data/spec/web_spec.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
  require 'spec_helper'
3
- require 'rack/test'
4
3
  require 'rspec-html-matchers'
5
4
  require 'sidekiq/killswitch/web'
6
5
 
@@ -10,6 +9,12 @@ RSpec.describe Sidekiq::Killswitch::Web do
10
9
 
11
10
  let(:app) { Sidekiq::Web }
12
11
 
12
+ before do
13
+ # Hash is not a real session, but it seems to provide a session-compatible interface,
14
+ # and we're only using #[] and #delete methods.
15
+ env "rack.session", {}
16
+ end
17
+
13
18
  def expect_redirect_to_root_page(response)
14
19
  expect(response.status).to be(302)
15
20
  expect(response.headers['Location']).to eq("http://#{rack_mock_session.default_host}/kill-switches")
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sidekiq-killswitch
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yuriy Naidyon
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-07-01 00:00:00.000000000 Z
11
+ date: 2024-11-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sidekiq
@@ -96,7 +96,6 @@ files:
96
96
  - Rakefile
97
97
  - examples/killswitch-web-ui.png
98
98
  - examples/square-logo.png
99
- - lib/sidekiq/extensions/dead_set.rb
100
99
  - lib/sidekiq/killswitch.rb
101
100
  - lib/sidekiq/killswitch/config.rb
102
101
  - lib/sidekiq/killswitch/middleware/client.rb
@@ -106,7 +105,6 @@ files:
106
105
  - lib/sidekiq/killswitch/web.rb
107
106
  - sidekiq-killswitch.gemspec
108
107
  - spec/config_spec.rb
109
- - spec/dead_set_spec.rb
110
108
  - spec/killswitch_spec.rb
111
109
  - spec/middleware/client_spec.rb
112
110
  - spec/middleware/server_spec.rb
@@ -134,13 +132,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
134
132
  - !ruby/object:Gem::Version
135
133
  version: '0'
136
134
  requirements: []
137
- rubygems_version: 3.4.19
135
+ rubygems_version: 3.3.26
138
136
  signing_key:
139
137
  specification_version: 4
140
138
  summary: Cross-host Sidekiq worker killswitches
141
139
  test_files:
142
140
  - spec/config_spec.rb
143
- - spec/dead_set_spec.rb
144
141
  - spec/killswitch_spec.rb
145
142
  - spec/middleware/client_spec.rb
146
143
  - spec/middleware/server_spec.rb
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
- require 'sidekiq/api'
3
-
4
- # this is a monkey-patch!
5
- # TODO: delete this patch after we explicitly depend on Sidekiq version that
6
- # includes this PR: https://github.com/mperham/sidekiq/pull/3573
7
-
8
- module Sidekiq
9
- module DeadSetKill
10
- def kill(message)
11
- now = Time.now.to_f
12
- Sidekiq.redis do |conn|
13
- conn.multi do
14
- conn.zadd(name, now.to_f.to_s, message)
15
- conn.zremrangebyscore(name, '-inf', now - self.class.timeout)
16
- conn.zremrangebyrank(name, 0, - self.class.max_jobs)
17
- end
18
- end
19
- end
20
- end
21
- end
22
-
23
- Sidekiq::DeadSet.include(Sidekiq::DeadSetKill) unless Sidekiq::DeadSet.method_defined?(:kill)
@@ -1,47 +0,0 @@
1
- # frozen_string_literal: true
2
- require 'spec_helper'
3
-
4
- RSpec.describe Sidekiq::DeadSet do
5
- let(:dead_set) { Sidekiq::DeadSet.new }
6
-
7
- describe '#kill' do
8
- it 'should put passed serialized job to the "dead" sorted set' do
9
- serialized_job = Sidekiq.dump_json(jid: '123123', class: 'SomeWorker', args: [])
10
- dead_set.kill(serialized_job)
11
-
12
- expect(dead_set.find_job('123123').value).to eq(serialized_job)
13
- end
14
-
15
- it 'should remove dead jobs older than Sidekiq::DeadSet.timeout' do
16
- allow(Sidekiq::DeadSet).to receive(:timeout).and_return(10)
17
- time_now = Time.now
18
-
19
- stub_time_now(time_now - 11)
20
- dead_set.kill(Sidekiq.dump_json({jid: '000103', class: 'MyWorker3', args: []})) # the oldest
21
-
22
- stub_time_now(time_now - 9)
23
- dead_set.kill(Sidekiq.dump_json({jid: '000102', class: 'MyWorker2', args: []}))
24
-
25
- stub_time_now(time_now)
26
- dead_set.kill(Sidekiq.dump_json({jid: '000101', class: 'MyWorker1', args: []}))
27
-
28
- stub_time_now(time_now)
29
-
30
- expect(dead_set.find_job('000103')).to be_falsey
31
- expect(dead_set.find_job('000102')).to be_truthy
32
- expect(dead_set.find_job('000101')).to be_truthy
33
- end
34
-
35
- it 'should remove all but last Sidekiq::DeadSet.max_jobs-1 jobs' do
36
- allow(Sidekiq::DeadSet).to receive(:max_jobs).and_return(3)
37
-
38
- dead_set.kill(Sidekiq.dump_json({jid: '000101', class: 'MyWorker1', args: []}))
39
- dead_set.kill(Sidekiq.dump_json({jid: '000102', class: 'MyWorker2', args: []}))
40
- dead_set.kill(Sidekiq.dump_json({jid: '000103', class: 'MyWorker3', args: []}))
41
-
42
- expect(dead_set.find_job('000101')).to be_falsey
43
- expect(dead_set.find_job('000102')).to be_truthy
44
- expect(dead_set.find_job('000103')).to be_truthy
45
- end
46
- end
47
- end