sidekiq-killswitch 1.0.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/.rubocop.yml +679 -0
- data/CHANGES.md +2 -0
- data/Gemfile +4 -0
- data/LICENSE +201 -0
- data/README.md +155 -0
- data/Rakefile +18 -0
- data/examples/killswitch-web-ui.png +0 -0
- data/examples/square-logo.png +0 -0
- data/lib/sidekiq/extensions/dead_set.rb +23 -0
- data/lib/sidekiq/killswitch/config.rb +37 -0
- data/lib/sidekiq/killswitch/middleware/client.rb +20 -0
- data/lib/sidekiq/killswitch/middleware/load_all.rb +19 -0
- data/lib/sidekiq/killswitch/middleware/server.rb +20 -0
- data/lib/sidekiq/killswitch/version.rb +7 -0
- data/lib/sidekiq/killswitch/web.rb +62 -0
- data/lib/sidekiq/killswitch.rb +92 -0
- data/sidekiq-killswitch.gemspec +25 -0
- data/spec/config_spec.rb +33 -0
- data/spec/dead_set_spec.rb +47 -0
- data/spec/killswitch_spec.rb +145 -0
- data/spec/middleware/client_spec.rb +25 -0
- data/spec/middleware/server_spec.rb +46 -0
- data/spec/spec_helper.rb +23 -0
- data/spec/web_spec.rb +110 -0
- data/web/locales/en.yml +15 -0
- data/web/views/kill_switches.html.erb +75 -0
- metadata +148 -0
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require File.expand_path('../lib/sidekiq/killswitch/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.name = 'sidekiq-killswitch'
|
6
|
+
gem.version = Sidekiq::Killswitch::VERSION
|
7
|
+
gem.summary = 'Cross-host Sidekiq worker killswitches'
|
8
|
+
gem.authors = ['Yuriy Naidyon']
|
9
|
+
gem.email = 'yurokle@gmail.com'
|
10
|
+
gem.license = 'Apache-2.0'
|
11
|
+
gem.homepage = 'https://github.com/square/sidekiq-killswitch'
|
12
|
+
|
13
|
+
gem.files = `git ls-files`.split($RS)
|
14
|
+
gem.test_files = gem.files.grep(%r{spec/})
|
15
|
+
gem.require_paths = ['lib']
|
16
|
+
gem.required_ruby_version = '>= 2.2.2'
|
17
|
+
gem.metadata['allowed_push_host'] = 'https://rubygems.org'
|
18
|
+
|
19
|
+
gem.add_runtime_dependency 'sidekiq', '>= 3'
|
20
|
+
|
21
|
+
gem.add_development_dependency 'rspec', '~> 3.6'
|
22
|
+
gem.add_development_dependency 'rack-test'
|
23
|
+
gem.add_development_dependency 'rspec-html-matchers'
|
24
|
+
gem.add_development_dependency 'rubocop', '~> 0.49.1'
|
25
|
+
end
|
data/spec/config_spec.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
RSpec.describe Sidekiq::Killswitch::Config do
|
5
|
+
let(:config) { Sidekiq::Killswitch::Config.new }
|
6
|
+
|
7
|
+
describe '#web_ui_worker_validator' do
|
8
|
+
it 'should to string presence validation by default' do
|
9
|
+
expect(config.web_ui_worker_validator.call(nil)).to be_falsey
|
10
|
+
expect(config.web_ui_worker_validator.call('')).to be_falsey
|
11
|
+
expect(config.web_ui_worker_validator.call('MyWorker')).to be_truthy
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#validate_worker_class_in_web' do
|
16
|
+
it 'should set Sidekiq::Worker module inclusion check as validator' do
|
17
|
+
stub_const('GoodWorker', Class.new {
|
18
|
+
include Sidekiq::Worker
|
19
|
+
})
|
20
|
+
stub_const('AlsoGoodWorker', Class.new(GoodWorker) {})
|
21
|
+
stub_const('BadWorker', Class.new {})
|
22
|
+
|
23
|
+
config.validate_worker_class_in_web
|
24
|
+
|
25
|
+
expect(config.web_ui_worker_validator.call('GoodWorker')).to be_truthy
|
26
|
+
expect(config.web_ui_worker_validator.call('AlsoGoodWorker')).to be_truthy
|
27
|
+
|
28
|
+
expect(config.web_ui_worker_validator.call('BadWorker')).to be_falsey
|
29
|
+
expect(config.web_ui_worker_validator.call('')).to be_falsey
|
30
|
+
expect(config.web_ui_worker_validator.call('Sidekiq::Worker')).to be_falsey
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,47 @@
|
|
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
|
@@ -0,0 +1,145 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
RSpec.describe Sidekiq::Killswitch do
|
5
|
+
# !!!!! HERE BE DRAGONS !!!!!
|
6
|
+
# Make sure to return test config to the working state after testing ...
|
7
|
+
# ... consider using Rspec.around wrapper:
|
8
|
+
#
|
9
|
+
# around do |example|
|
10
|
+
# original_test_logger = Sidekiq::Killswitch.logger
|
11
|
+
# example.run
|
12
|
+
# Sidekiq::Killswitch.logger = original_test_logger
|
13
|
+
# end
|
14
|
+
|
15
|
+
around do |example|
|
16
|
+
original_test_logger = Sidekiq::Killswitch.config.logger
|
17
|
+
|
18
|
+
example.run
|
19
|
+
|
20
|
+
Sidekiq::Killswitch.config.logger = original_test_logger
|
21
|
+
end
|
22
|
+
|
23
|
+
let(:worker_name) { 'SomeWorker' }
|
24
|
+
|
25
|
+
describe '.configure' do
|
26
|
+
describe '.logger= ' do
|
27
|
+
it 'should allow to set the logger' do
|
28
|
+
logger = double
|
29
|
+
|
30
|
+
Sidekiq::Killswitch.configure do |config|
|
31
|
+
config.logger = logger
|
32
|
+
end
|
33
|
+
|
34
|
+
expect(Sidekiq::Killswitch.logger).to eq(logger)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '.blackhole_add_worker' do
|
40
|
+
it 'should mark a worker as blackholed in Redis' do
|
41
|
+
time_now = stub_time_now
|
42
|
+
|
43
|
+
Sidekiq::Killswitch.blackhole_add_worker(worker_name)
|
44
|
+
|
45
|
+
Sidekiq::Killswitch.redis_pool do |redis|
|
46
|
+
expect(redis.hget(Sidekiq::Killswitch::BLACKHOLE_WORKERS_KEY_NAME, worker_name)).to eq(time_now.to_s)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should accept class object as a parameter' do
|
51
|
+
time_now = stub_time_now
|
52
|
+
stub_const('AnotherWorker', Class.new {})
|
53
|
+
|
54
|
+
Sidekiq::Killswitch.blackhole_add_worker(AnotherWorker)
|
55
|
+
|
56
|
+
Sidekiq::Killswitch.redis_pool do |redis|
|
57
|
+
expect(redis.hget(Sidekiq::Killswitch::BLACKHOLE_WORKERS_KEY_NAME, 'AnotherWorker')).to eq(time_now.to_s)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe '.blackhole_remove_worker' do
|
63
|
+
it 'should remove worker from the list of blackholed workers' do
|
64
|
+
Sidekiq::Killswitch.blackhole_add_worker(worker_name)
|
65
|
+
Sidekiq::Killswitch.blackhole_remove_worker(worker_name)
|
66
|
+
|
67
|
+
Sidekiq::Killswitch.redis_pool do |redis|
|
68
|
+
expect(redis.hexists(Sidekiq::Killswitch::BLACKHOLE_WORKERS_KEY_NAME, worker_name)).to be_falsey
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe '.blackhole_worker?' do
|
74
|
+
it 'should return true for blackholed workers' do
|
75
|
+
Sidekiq::Killswitch.blackhole_add_worker(worker_name)
|
76
|
+
expect(Sidekiq::Killswitch.blackhole_worker?(worker_name)).to be_truthy
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'should return false for non-blackholed workers' do
|
80
|
+
expect(Sidekiq::Killswitch.blackhole_worker?(worker_name)).to be_falsey
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe '.blackhole_workers' do
|
85
|
+
it 'should return a list of all blackholed workers with "added at" timestamps' do
|
86
|
+
first_worker_added_at = stub_time_now
|
87
|
+
Sidekiq::Killswitch.blackhole_add_worker('FirstWorker')
|
88
|
+
second_worker_added_at = stub_time_now(first_worker_added_at + 1)
|
89
|
+
Sidekiq::Killswitch.blackhole_add_worker('SecondWorker')
|
90
|
+
|
91
|
+
expect(Sidekiq::Killswitch.blackhole_workers).to eq({
|
92
|
+
'FirstWorker' => first_worker_added_at.to_s,
|
93
|
+
'SecondWorker' => second_worker_added_at.to_s
|
94
|
+
})
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe '.dead_queue_add_worker' do
|
99
|
+
it 'should mark a worker as a "dead queue worker" in Redis' do
|
100
|
+
time_now = stub_time_now
|
101
|
+
|
102
|
+
Sidekiq::Killswitch.dead_queue_add_worker(worker_name)
|
103
|
+
|
104
|
+
Sidekiq::Killswitch.redis_pool do |redis|
|
105
|
+
expect(redis.hget(Sidekiq::Killswitch::DEAD_QUEUE_WORKERS_KEY_NAME, worker_name)).to eq(time_now.to_s)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe '.dead_queue_remove_worker' do
|
111
|
+
it 'should remove worker from the list of dead queue workers' do
|
112
|
+
Sidekiq::Killswitch.dead_queue_add_worker(worker_name)
|
113
|
+
Sidekiq::Killswitch.dead_queue_remove_worker(worker_name)
|
114
|
+
|
115
|
+
Sidekiq::Killswitch.redis_pool do |redis|
|
116
|
+
expect(redis.hexists(Sidekiq::Killswitch::DEAD_QUEUE_WORKERS_KEY_NAME, worker_name)).to be_falsey
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
describe '.dead_queue_worker?' do
|
122
|
+
it 'should return true for dead queue workers' do
|
123
|
+
Sidekiq::Killswitch.dead_queue_add_worker(worker_name)
|
124
|
+
expect(Sidekiq::Killswitch.dead_queue_worker?(worker_name)).to be_truthy
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'should return false for non-dead-queue workers' do
|
128
|
+
expect(Sidekiq::Killswitch.dead_queue_worker?(worker_name)).to be_falsey
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
describe '.dead_queue_workers' do
|
133
|
+
it 'should return a list of all dead queue workers with "added at" timestamps' do
|
134
|
+
first_worker_added_at = stub_time_now
|
135
|
+
Sidekiq::Killswitch.dead_queue_add_worker('FirstWorker')
|
136
|
+
second_worker_added_at = stub_time_now(first_worker_added_at + 1)
|
137
|
+
Sidekiq::Killswitch.dead_queue_add_worker('SecondWorker')
|
138
|
+
|
139
|
+
expect(Sidekiq::Killswitch.dead_queue_workers).to eq({
|
140
|
+
'FirstWorker' => first_worker_added_at.to_s,
|
141
|
+
'SecondWorker' => second_worker_added_at.to_s
|
142
|
+
})
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
RSpec.describe Sidekiq::Killswitch::Middleware::Client do
|
5
|
+
let(:client_middleware) { Sidekiq::Killswitch::Middleware::Client.new }
|
6
|
+
|
7
|
+
describe '#call' do
|
8
|
+
it 'should return false for blackholed workers' do
|
9
|
+
stub_const('DisabledWorker', Class.new {})
|
10
|
+
|
11
|
+
Sidekiq::Killswitch.blackhole_add_worker(DisabledWorker)
|
12
|
+
Sidekiq::Killswitch.blackhole_add_worker('MyWorker')
|
13
|
+
|
14
|
+
expect(client_middleware.call(DisabledWorker, {}, nil, nil) { 123 }).to eq(false)
|
15
|
+
expect(client_middleware.call('MyWorker', {}, nil, nil) { 123 }).to eq(false)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should return block result for not blockholed workers' do
|
19
|
+
stub_const('EnabledWorker', Class.new {})
|
20
|
+
|
21
|
+
expect(client_middleware.call(EnabledWorker, {}, nil, nil) { 'result' }).to eq('result')
|
22
|
+
expect(client_middleware.call('EnabledWorker', {}, nil, nil) { 123 }).to eq(123)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
RSpec.describe Sidekiq::Killswitch::Middleware::Server do
|
5
|
+
let(:server_middleware) { Sidekiq::Killswitch::Middleware::Server.new }
|
6
|
+
|
7
|
+
before do
|
8
|
+
stub_const('MyWorker', Class.new {
|
9
|
+
include Sidekiq::Worker
|
10
|
+
def perform; end
|
11
|
+
})
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#call' do
|
15
|
+
context 'for blackholed workers' do
|
16
|
+
it 'should not run block' do
|
17
|
+
Sidekiq::Killswitch.blackhole_add_worker(MyWorker)
|
18
|
+
|
19
|
+
expect do
|
20
|
+
server_middleware.call(MyWorker.new, {}, nil) { raise 'Should not run' }
|
21
|
+
end.to_not raise_error
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'for dead-queued workers' do
|
26
|
+
it 'should send a job to the morgue' do
|
27
|
+
Sidekiq::Killswitch.dead_queue_add_worker(MyWorker)
|
28
|
+
|
29
|
+
job_data = double
|
30
|
+
expect_any_instance_of(Sidekiq::DeadSet).to receive(:kill).with(job_data)
|
31
|
+
|
32
|
+
expect do
|
33
|
+
server_middleware.call(MyWorker.new, job_data, nil) { raise 'Should not run' }
|
34
|
+
end.to_not raise_error
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'for non-marked workers' do
|
39
|
+
it 'should run passed block' do
|
40
|
+
checkpoint = double
|
41
|
+
expect(checkpoint).to receive(:check)
|
42
|
+
server_middleware.call(MyWorker.new, {}, nil) { checkpoint.check }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'rspec'
|
3
|
+
require 'logger'
|
4
|
+
require 'sidekiq/testing'
|
5
|
+
require 'sidekiq/killswitch'
|
6
|
+
|
7
|
+
ENV['RACK_ENV'] = 'test' # Disable CSRF protection for Sidekiq Web app
|
8
|
+
|
9
|
+
Sidekiq::Killswitch.configure do |config|
|
10
|
+
config.logger = Logger.new('/dev/null')
|
11
|
+
end
|
12
|
+
|
13
|
+
RSpec.configure do |config|
|
14
|
+
config.disable_monkey_patching!
|
15
|
+
config.before do
|
16
|
+
Sidekiq::Killswitch.redis_pool { |c| c.flushdb }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def stub_time_now(time_now = Time.now)
|
21
|
+
allow(Time).to receive(:now).and_return(time_now)
|
22
|
+
time_now
|
23
|
+
end
|
data/spec/web_spec.rb
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'rack/test'
|
4
|
+
require 'rspec-html-matchers'
|
5
|
+
require 'sidekiq/killswitch/web'
|
6
|
+
|
7
|
+
RSpec.describe Sidekiq::Killswitch::Web do
|
8
|
+
include Rack::Test::Methods
|
9
|
+
include RSpecHtmlMatchers
|
10
|
+
|
11
|
+
let(:app) { Sidekiq::Web }
|
12
|
+
|
13
|
+
def expect_redirect_to_root_page(response)
|
14
|
+
expect(response.status).to be(302)
|
15
|
+
expect(response.headers['Location']).to eq("http://#{rack_mock_session.default_host}/kill-switches")
|
16
|
+
end
|
17
|
+
|
18
|
+
describe 'GET /kill-switches' do
|
19
|
+
it 'should list blackholed workers' do
|
20
|
+
Sidekiq::Killswitch.blackhole_add_worker('WorkerOne')
|
21
|
+
Sidekiq::Killswitch.blackhole_add_worker('WorkerTwo')
|
22
|
+
|
23
|
+
response = get('/kill-switches')
|
24
|
+
expect(response.status).to be(200)
|
25
|
+
|
26
|
+
expect(response.body).to have_tag('.blackhole-workers') do
|
27
|
+
with_text('WorkerOne')
|
28
|
+
with_text('WorkerTwo')
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should list dead-queued workers' do
|
33
|
+
Sidekiq::Killswitch.dead_queue_add_worker('DeadWorkerOne')
|
34
|
+
Sidekiq::Killswitch.dead_queue_add_worker('DeadWorkerTwo')
|
35
|
+
|
36
|
+
response = get('/kill-switches')
|
37
|
+
|
38
|
+
expect(response.body).to have_tag('.dead-queue-workers') do
|
39
|
+
with_text('DeadWorkerOne')
|
40
|
+
with_text('DeadWorkerTwo')
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe 'POST /kill-switches/blackhole_add' do
|
46
|
+
it 'should blackhole passed worker' do
|
47
|
+
response = post('/kill-switches/blackhole_add', worker_name: 'BlackholedWorker')
|
48
|
+
|
49
|
+
expect_redirect_to_root_page(response)
|
50
|
+
expect(Sidekiq::Killswitch.blackhole_worker?('BlackholedWorker')).to be_truthy
|
51
|
+
end
|
52
|
+
|
53
|
+
describe 'validation' do
|
54
|
+
around do |example|
|
55
|
+
default_validator = Sidekiq::Killswitch.config.web_ui_worker_validator
|
56
|
+
example.run
|
57
|
+
Sidekiq::Killswitch.config.web_ui_worker_validator = default_validator
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'should perform basic default validation' do
|
61
|
+
post('/kill-switches/blackhole_add', worker_name: '')
|
62
|
+
follow_redirect!
|
63
|
+
|
64
|
+
expect(last_response.body).to have_tag('.error-message', text: 'Error: Invalid worker name!')
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'should perform custom validation' do
|
68
|
+
Sidekiq::Killswitch.config.web_ui_worker_validator = ->(name) { name.end_with?('BlockedWorker') }
|
69
|
+
|
70
|
+
post('/kill-switches/blackhole_add', worker_name: 'BadWorker')
|
71
|
+
follow_redirect!
|
72
|
+
expect(last_response.body).to have_tag('.error-message', text: 'Error: Invalid worker name!')
|
73
|
+
|
74
|
+
post('/kill-switches/blackhole_add', worker_name: 'MyBlockedWorker')
|
75
|
+
expect(Sidekiq::Killswitch.blackhole_worker?('MyBlockedWorker')).to be_truthy
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe 'POST /kill-switches/blackhole_remove' do
|
81
|
+
it 'should remove worker from blackhole' do
|
82
|
+
Sidekiq::Killswitch.blackhole_add_worker('BlakcholedWorker')
|
83
|
+
|
84
|
+
response = post('/kill-switches/blackhole_remove', worker_name: 'BlackholedWorker')
|
85
|
+
|
86
|
+
expect_redirect_to_root_page(response)
|
87
|
+
expect(Sidekiq::Killswitch.blackhole_worker?('BlackholedWorker')).to be_falsey
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe 'POST /kill-switches/dead_queue_add' do
|
92
|
+
it 'should add passed worker to dead queue' do
|
93
|
+
response = post('/kill-switches/dead_queue_add', worker_name: 'DeadWorker')
|
94
|
+
|
95
|
+
expect_redirect_to_root_page(response)
|
96
|
+
expect(Sidekiq::Killswitch.dead_queue_worker?('DeadWorker')).to be_truthy
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe 'POST /kill-switches/dead_queue_remove' do
|
101
|
+
it 'should remove worker from dead queue' do
|
102
|
+
Sidekiq::Killswitch.dead_queue_add_worker('DeadWorker')
|
103
|
+
|
104
|
+
response = post('/kill-switches/dead_queue_remove', worker_name: 'DeadWorker')
|
105
|
+
|
106
|
+
expect_redirect_to_root_page(response)
|
107
|
+
expect(Sidekiq::Killswitch.dead_queue_worker?('DeadWorker')).to be_falsey
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
data/web/locales/en.yml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
en:
|
2
|
+
kill_switches: Kill Switches
|
3
|
+
blackholed_workers: Blackholed Workers
|
4
|
+
dead_queue_workers: Dead Queue Workers
|
5
|
+
are_you_sure: Are you sure?
|
6
|
+
blackhole: Blackhole
|
7
|
+
disabled_at: Disabled at
|
8
|
+
dead_queued_at: Dead-queued at
|
9
|
+
blackholed_at: Blackholed at
|
10
|
+
send_to_dead_queue: Send to dead queue
|
11
|
+
class: Class
|
12
|
+
kill: Kill
|
13
|
+
resurrect: Resurrect
|
14
|
+
resurrect_worker: Resurrect %{worker}?
|
15
|
+
invalid_worker_error: "Error: Invalid worker name!"
|
@@ -0,0 +1,75 @@
|
|
1
|
+
<% if @worker_name_invalid %>
|
2
|
+
<h4 class="error-message alert alert-danger"><%= t('invalid_worker_error')%></h4>
|
3
|
+
<% end %>
|
4
|
+
|
5
|
+
<h3><%= t('blackholed_workers')%></h3>
|
6
|
+
|
7
|
+
<form action="<%= root_path %>kill-switches/blackhole_add" method="post" style="margin-bottom: 4px;">
|
8
|
+
<%= csrf_tag %>
|
9
|
+
<input name="worker_name" />
|
10
|
+
<input class="btn btn-danger btn-xs" type="submit" value="<%= t('blackhole')%>" data-confirm="<%= t('are_you_sure')%>" />
|
11
|
+
</form>
|
12
|
+
|
13
|
+
<div class="table_container">
|
14
|
+
<table class="blackhole-workers table table-hover table-bordered table-striped table-white">
|
15
|
+
<thead>
|
16
|
+
<tr>
|
17
|
+
<th><%= t('class')%></th>
|
18
|
+
<th style="width: 100%;"><%= t('blackholed_at')%></th>
|
19
|
+
<th></th>
|
20
|
+
</tr>
|
21
|
+
</thead>
|
22
|
+
|
23
|
+
<tbody>
|
24
|
+
<% @blackhole_workers.each do |worker_name, disabled_at| %>
|
25
|
+
<tr>
|
26
|
+
<td><%= worker_name %></td>
|
27
|
+
<td><%= disabled_at %></td>
|
28
|
+
<td class="text-center">
|
29
|
+
<form action="<%= root_path %>kill-switches/blackhole_remove" method="post">
|
30
|
+
<%= csrf_tag %>
|
31
|
+
<input type="hidden" name="worker_name" value="<%= worker_name %>" />
|
32
|
+
<input class="btn btn-primary btn-xs pull-right" type="submit" value="<%= t('restore')%>" data-confirm="<%= t('restore_worker', worker: worker_name) %>" />
|
33
|
+
</form>
|
34
|
+
</td>
|
35
|
+
</tr>
|
36
|
+
<% end %>
|
37
|
+
</tbody>
|
38
|
+
</table>
|
39
|
+
</div>
|
40
|
+
|
41
|
+
<h3><%= t('dead_queue_workers') %></h3>
|
42
|
+
|
43
|
+
<form action="<%= root_path %>kill-switches/dead_queue_add" method="post" style="margin-bottom: 4px;">
|
44
|
+
<%= csrf_tag %>
|
45
|
+
<input name="worker_name" />
|
46
|
+
<input class="btn btn-danger btn-xs" type="submit" value="<%= t('send_to_dead_queue') %>" data-confirm="<%= t('are_you_sure')%>" />
|
47
|
+
</form>
|
48
|
+
|
49
|
+
<div class="table_container">
|
50
|
+
<table class="dead-queue-workers table table-hover table-bordered table-striped table-white">
|
51
|
+
<thead>
|
52
|
+
<tr>
|
53
|
+
<th><%= t('class')%></th>
|
54
|
+
<th style="width: 100%;"><%= t('dead_queued_at')%></th>
|
55
|
+
<th></th>
|
56
|
+
</tr>
|
57
|
+
</thead>
|
58
|
+
|
59
|
+
<tbody>
|
60
|
+
<% @dead_queue_workers.each do |worker_name, disabled_at| %>
|
61
|
+
<tr>
|
62
|
+
<td><%= worker_name %></td>
|
63
|
+
<td><%= disabled_at %></td>
|
64
|
+
<td class="text-center">
|
65
|
+
<form action="<%= root_path %>kill-switches/dead_queue_remove" method="post">
|
66
|
+
<%= csrf_tag %>
|
67
|
+
<input type="hidden" name="worker_name" value="<%= worker_name %>" />
|
68
|
+
<input class="btn btn-primary btn-xs pull-right" type="submit" value="<%= t('resurrect')%>" data-confirm="<%= t('resurrect_worker', worker: worker_name) %>" />
|
69
|
+
</form>
|
70
|
+
</td>
|
71
|
+
</tr>
|
72
|
+
<% end %>
|
73
|
+
</tbody>
|
74
|
+
</table>
|
75
|
+
</div>
|