sidekiq-worker-killer 0.4.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: c2b88a4d00042d82a27ebd81fa27832f01873618
4
- data.tar.gz: 010d2676048b457204d403509774c4e013cd39d4
2
+ SHA256:
3
+ metadata.gz: f8573256c162630662fbb9be660375da63c3c8cbe3fb11d9851e36b1c0456eff
4
+ data.tar.gz: 63a6bea822d499f22f283f704f80e0954ac006ed442f6cb7632fa204602051f3
5
5
  SHA512:
6
- metadata.gz: 9aef7ae408f33ed04a2cbe81ba673887d877762c803482da841a25c0878b2c91e96e6eb8b4eabfddcbcfb42b8bf7ce56e218463df867af44fadad7afb4a6a0c9
7
- data.tar.gz: 4c9cfa47bdb45445f6647ca0297e3118f4f37cc675759a3e292a96e701577c385c6f7bcce832cd8c5082f59acce4449aefad7e92160e59f8049eefa5499d95c7
6
+ metadata.gz: c1fe7ab3d39860cbd742af569a3e5b3a37173bbdffa751ebc76aae1cbf67d09a5745991e8ad9c5b50671705b110abeab3ee4124e69c3ebbccc658579409cbd6d
7
+ data.tar.gz: f65acd7d78a86152a2d04cd5c4ef0046885366540c362fe0a8c61caa4f1d04d4263f338bd9769c00ea09530151b9a8da48f34cf71377ecfec6517c4c36075d80
data/README.md CHANGED
@@ -5,7 +5,18 @@
5
5
 
6
6
  [Sidekiq](https://github.com/mperham/sidekiq) is probably the best background processing framework today. At the same time, memory leaks are very hard to tackle in Ruby and we often find ourselves with growing memory consumption. Instead of spending herculean effort fixing leaks, why not kill your processes when they got to be too large?
7
7
 
8
- Highly inspired by [Gitlab Sidekiq MemoryKiller](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/sidekiq_middleware/shutdown.rb) and [Noxa Sidekiq killer](https://github.com/Noxa/sidekiq-killer).
8
+ Highly inspired by [Gitlab Sidekiq MemoryKiller](https://gitlab.com/gitlab-org/gitlab-foss/-/blob/39c1731a53d1014eab7c876d70632b1abf738712/lib/gitlab/sidekiq_middleware/shutdown.rb) and [Noxa Sidekiq killer](https://github.com/Noxa/sidekiq-killer).
9
+
10
+ ---
11
+ **NOTE**
12
+
13
+ This gem needs to get the used memory of the Sidekiq process. For
14
+ this we use [GetProcessGem](https://github.com/schneems/get_process_mem),
15
+ but be aware that if you are running Sidekiq in Heroku(or any container) the
16
+ memory usage will
17
+ [not be accurate](https://github.com/schneems/get_process_mem/issues/7).
18
+
19
+ ---
9
20
 
10
21
  quick-refs: [install](#install) | [usage](#usage) | [available options](#available-options) | [development](#development)
11
22
 
@@ -31,15 +42,30 @@ end
31
42
 
32
43
  ## Available options
33
44
 
34
- The following options can be overrided.
45
+ The following options can be overridden.
35
46
 
36
47
  | Option | Defaults | Description |
37
48
  | ------- | ------- | ----------- |
38
- | max_rss | 0 MB (disabled) | max RSS in megabytes. Above this, shutdown will be triggered. |
39
- | grace_time | 900 seconds | when shutdown is triggered, the Sidekiq process will not accept new job and wait at most 15 minutes for running jobs to finish. If Float::INFINITY specified, will wait forever |
40
- | shutdown_wait | 30 seconds | when the grace time expires, still running jobs get 30 seconds to terminate. After that, kill signal is triggered. |
41
- | kill_signal | SIGKILL | Signal to use kill Sidekiq process if it doesn't terminate. |
42
- | gc | true | Try to run garbage collection before Sidekiq process terminate in case of max_rss exceeded |
49
+ | max_rss | 0 MB (disabled) | Max RSS in megabytes used by the Sidekiq process. Above this, shutdown will be triggered. |
50
+ | grace_time | 900 seconds | When shutdown is triggered, the Sidekiq process will not accept new job and wait at most 15 minutes for running jobs to finish. If Float::INFINITY specified, will wait forever. |
51
+ | shutdown_wait | 30 seconds | When the grace time expires, still running jobs get 30 seconds to stop. After that, kill signal is triggered. |
52
+ | kill_signal | SIGKILL | Signal to use to kill Sidekiq process if it doesn't stop. |
53
+ | gc | true | Try to run garbage collection before Sidekiq process stops in case of exceeded max_rss. |
54
+ | skip_shutdown_if | proc {false} | Executes a block of code after max_rss exceeds but before requesting shutdown. |
55
+
56
+ *skip_shutdown_if* is expected to return anything other than `false` or `nil` to skip shutdown.
57
+
58
+ ```ruby
59
+ require 'sidekiq/worker_killer'
60
+
61
+ Sidekiq.configure_server do |config|
62
+ config.server_middleware do |chain|
63
+ chain.add Sidekiq::WorkerKiller, max_rss: 480, skip_shutdown_if: ->(worker, job, queue) do
64
+ worker.to_s == 'LongWorker'
65
+ end
66
+ end
67
+ end
68
+ ```
43
69
 
44
70
  ## Development
45
71
 
@@ -60,4 +86,4 @@ See the list of [contributors](https://github.com/klaxit/sidekiq-worker-killer/c
60
86
 
61
87
  ## License
62
88
 
63
- Please see LICENSE
89
+ Please see [LICENSE](https://github.com/klaxit/sidekiq-worker-killer/blob/master/LICENSE)
@@ -1,7 +1,7 @@
1
1
  # rubocop:disable Style/ClassAndModuleChildren
2
2
  module Sidekiq
3
3
  class WorkerKiller
4
- VERSION = "0.4.0".freeze
4
+ VERSION = "1.0.1".freeze
5
5
  end
6
6
  end
7
7
  # rubocop:enable Style/ClassAndModuleChildren
@@ -1,30 +1,71 @@
1
1
  require "get_process_mem"
2
2
  require "sidekiq"
3
- require "sidekiq/util"
3
+ begin
4
+ require "sidekiq/util"
5
+ SidekiqComponent = Sidekiq::Util
6
+ rescue LoadError
7
+ require "sidekiq/middleware/modules"
8
+ SidekiqComponent = Sidekiq::ServerMiddleware
9
+ end
10
+ require "sidekiq/api"
4
11
 
5
12
  # Sidekiq server middleware. Kill worker when the RSS memory exceeds limit
6
13
  # after a given grace time.
7
14
  class Sidekiq::WorkerKiller
8
- include Sidekiq::Util
15
+ include SidekiqComponent
9
16
 
10
17
  MUTEX = Mutex.new
11
18
 
19
+ # @param [Hash] options
20
+ # @option options [Integer] max_rss
21
+ # Max RSS in MB. Above this, shutdown will be triggered.
22
+ # (default: `0` (disabled))
23
+ # @option options [Integer] grace_time
24
+ # When shutdown is triggered, the Sidekiq process will not accept new job
25
+ # and wait at most 15 minutes for running jobs to finish.
26
+ # If Float::INFINITY is specified, will wait forever. (default: `900`)
27
+ # @option options [Integer] shutdown_wait
28
+ # when the grace time expires, still running jobs get 30 seconds to
29
+ # stop. After that, kill signal is triggered. (default: `30`)
30
+ # @option options [String] kill_signal
31
+ # Signal to use to kill Sidekiq process if it doesn't stop.
32
+ # (default: `"SIGKILL"`)
33
+ # @option options [Boolean] gc
34
+ # Try to run garbage collection before Sidekiq process stops in case
35
+ # of exceeded max_rss. (default: `true`)
36
+ # @option options [Proc] skip_shutdown_if
37
+ # Executes a block of code after max_rss exceeds but before requesting
38
+ # shutdown. (default: `proc {false}`)
12
39
  def initialize(options = {})
13
40
  @max_rss = options.fetch(:max_rss, 0)
14
41
  @grace_time = options.fetch(:grace_time, 15 * 60)
15
42
  @shutdown_wait = options.fetch(:shutdown_wait, 30)
16
43
  @kill_signal = options.fetch(:kill_signal, "SIGKILL")
17
44
  @gc = options.fetch(:gc, true)
45
+ @skip_shutdown = options.fetch(:skip_shutdown_if, proc { false })
18
46
  end
19
47
 
20
- def call(_worker, _job, _queue)
48
+ # @param [String, Class] worker_class
49
+ # the string or class of the worker class being enqueued
50
+ # @param [Hash] job
51
+ # the full job payload
52
+ # @see https://github.com/mperham/sidekiq/wiki/Job-Format
53
+ # @param [String] queue
54
+ # the name of the queue the job was pulled from
55
+ # @yield the next middleware in the chain or the enqueuing of the job
56
+ def call(worker, job, queue)
21
57
  yield
22
58
  # Skip if the max RSS is not exceeded
23
59
  return unless @max_rss > 0
24
60
  return unless current_rss > @max_rss
25
61
  GC.start(full_mark: true, immediate_sweep: true) if @gc
26
62
  return unless current_rss > @max_rss
27
- # Launch the shutdown process
63
+ if skip_shutdown?(worker, job, queue)
64
+ warn "current RSS #{current_rss} exceeds maximum RSS #{@max_rss}, " \
65
+ "however shutdown will be ignored"
66
+ return
67
+ end
68
+
28
69
  warn "current RSS #{current_rss} of #{identity} exceeds " \
29
70
  "maximum RSS #{@max_rss}"
30
71
  request_shutdown
@@ -32,6 +73,10 @@ class Sidekiq::WorkerKiller
32
73
 
33
74
  private
34
75
 
76
+ def skip_shutdown?(worker, job, queue)
77
+ @skip_shutdown.respond_to?(:call) && @skip_shutdown.call(worker, job, queue)
78
+ end
79
+
35
80
  def request_shutdown
36
81
  # In another thread to allow undelying job to finish
37
82
  Thread.new do
@@ -42,30 +87,28 @@ class Sidekiq::WorkerKiller
42
87
  end
43
88
 
44
89
  def shutdown
45
- warn "sending #{quiet_signal} to #{identity}"
46
- signal(quiet_signal, pid)
90
+ warn "sending quiet to #{identity}"
91
+ sidekiq_process.quiet!
92
+
93
+ sleep(5) # gives Sidekiq API 5 seconds to update ProcessSet
47
94
 
48
95
  warn "shutting down #{identity} in #{@grace_time} seconds"
49
96
  wait_job_finish_in_grace_time
50
97
 
51
- warn "sending SIGTERM to #{identity}"
52
- signal("SIGTERM", pid)
98
+ warn "stopping #{identity}"
99
+ sidekiq_process.stop!
53
100
 
54
101
  warn "waiting #{@shutdown_wait} seconds before sending " \
55
102
  "#{@kill_signal} to #{identity}"
56
103
  sleep(@shutdown_wait)
57
104
 
58
105
  warn "sending #{@kill_signal} to #{identity}"
59
- signal(@kill_signal, pid)
106
+ ::Process.kill(@kill_signal, ::Process.pid)
60
107
  end
61
108
 
62
109
  def wait_job_finish_in_grace_time
63
110
  start = Time.now
64
- loop do
65
- break if grace_time_exceeded?(start)
66
- break if no_jobs_on_quiet_processes?
67
- sleep(1)
68
- end
111
+ sleep(1) until grace_time_exceeded?(start) || jobs_finished?
69
112
  end
70
113
 
71
114
  def grace_time_exceeded?(start)
@@ -74,36 +117,23 @@ class Sidekiq::WorkerKiller
74
117
  start + @grace_time < Time.now
75
118
  end
76
119
 
77
- def no_jobs_on_quiet_processes?
78
- Sidekiq::ProcessSet.new.each do |process|
79
- return false if process["busy"] != 0 && process["quiet"] == "true"
80
- end
81
- true
120
+ def jobs_finished?
121
+ sidekiq_process.stopping? && sidekiq_process["busy"] == 0
82
122
  end
83
123
 
84
124
  def current_rss
85
125
  ::GetProcessMem.new.mb
86
126
  end
87
127
 
88
- def signal(signal, pid)
89
- ::Process.kill(signal, pid)
90
- end
91
-
92
- def pid
93
- ::Process.pid
128
+ def sidekiq_process
129
+ Sidekiq::ProcessSet.new.find do |process|
130
+ process["identity"] == identity
131
+ end || raise("No sidekiq worker with identity #{identity} found")
94
132
  end
95
133
 
96
134
  def identity
97
- "#{hostname}:#{pid}"
98
- end
99
-
100
- def quiet_signal
101
- if Gem::Version.new(Sidekiq::VERSION) >= Gem::Version.new("5.0")
102
- "TSTP"
103
- else
104
- "USR1"
105
- end
106
- end
135
+ config[:identity] || config["identity"]
136
+ end unless method_defined?(:identity)
107
137
 
108
138
  def warn(msg)
109
139
  Sidekiq.logger.warn(msg)
@@ -1,125 +1,219 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe Sidekiq::WorkerKiller do
4
+ let(:sidekiq_process_set) { instance_double(Sidekiq::ProcessSet) }
5
+ let(:sidekiq_process) { instance_double(Sidekiq::Process) }
4
6
 
5
7
  before do
6
8
  allow(subject).to receive(:warn) # silence "warn" logs
9
+ allow(subject).to receive(:sleep) # reduces tests running time
10
+ allow(sidekiq_process).to receive(:quiet!)
11
+ allow(sidekiq_process).to receive(:stop!)
12
+ allow(sidekiq_process).to receive(:stopping?)
7
13
  end
8
14
 
9
- describe "#call" do
10
- let(:worker){ double("worker") }
11
- let(:job){ double("job") }
12
- let(:queue){ double("queue") }
13
- it "should yield" do
14
- expect { |b|
15
- subject.call(worker, job, queue, &b)
16
- }.to yield_with_no_args
15
+ describe "#sidekiq_process" do
16
+ let(:identity) do
17
+ "foobar"
17
18
  end
18
- context "when current rss is over max rss" do
19
- subject{ described_class.new(max_rss: 2) }
20
- before do
21
- allow(subject).to receive(:current_rss).and_return(3)
19
+ let(:mock_processes) do
20
+ [{
21
+ "identity" => identity,
22
+ "tag" => "baz",
23
+ "started_at" => Time.now,
24
+ "concurrency" => 5,
25
+ "busy" => 2,
26
+ "queues" => %w[low medium high]
27
+ }]
28
+ end
29
+ it "finds the process by identity" do
30
+ if subject.respond_to?(:config=)
31
+ rspec_info "variant 6.5+: Sidekiq::ServerMiddleware"
32
+ subject.config = mock_processes.first
33
+ else
34
+ rspec_info "variant pre 6.5: Sidekiq::Util"
35
+ allow(subject).to receive(:identity).and_return(identity)
22
36
  end
23
- it "should request shutdown" do
24
- expect(subject).to receive(:request_shutdown)
25
- subject.call(worker, job, queue){}
37
+ allow(Sidekiq).to receive(:redis)
38
+ sidekiq_process_set = Sidekiq::ProcessSet.new
39
+ sidekiq_mock_processes = mock_processes.map {|mock_process|
40
+ Sidekiq::Process.new(mock_process)
41
+ }
42
+ allow(sidekiq_process_set).to receive(:each) {|&block|
43
+ sidekiq_mock_processes.each(&block)
44
+ }
45
+ expect(sidekiq_process_set.to_a.map(&:identity)).to eq([identity])
46
+ allow(Sidekiq::ProcessSet).to receive(:new).and_return(sidekiq_process_set)
47
+ expect(subject.send(:identity)).to eq(identity)
48
+ expect(subject.send(:sidekiq_process)).to be_a(Sidekiq::Process)
49
+ expect(subject.send(:sidekiq_process).identity).to eq(identity)
50
+ end
51
+ end
52
+
53
+ context "with stubbed sidekiq_process" do
54
+ before do
55
+ allow(Sidekiq::ProcessSet).to receive(:new) { sidekiq_process_set }
56
+ allow(sidekiq_process_set).to receive(:find) { sidekiq_process }
57
+ identity = "some-identity"
58
+ if subject.respond_to?(:config=)
59
+ rspec_info "variant 6.5+: Sidekiq::ServerMiddleware"
60
+ subject.config = { "identity" => identity }
61
+ else
62
+ rspec_info "variant pre 6.5: Sidekiq::Util"
63
+ allow(subject).to receive(:identity).and_return(identity)
26
64
  end
27
- it "should call garbage collect" do
28
- allow(subject).to receive(:request_shutdown)
29
- expect(GC).to receive(:start).with(full_mark: true, immediate_sweep: true)
30
- subject.call(worker, job, queue){}
65
+ end
66
+
67
+ describe "#call" do
68
+ let(:worker){ double("worker") }
69
+ let(:job){ double("job") }
70
+ let(:queue){ double("queue") }
71
+
72
+ it "should yield" do
73
+ expect { |b|
74
+ subject.call(worker, job, queue, &b)
75
+ }.to yield_with_no_args
31
76
  end
32
- context "when gc is false" do
33
- subject{ described_class.new(max_rss: 2, gc: false) }
34
- it "should not call garbage collect" do
35
- allow(subject).to receive(:request_shutdown)
36
- expect(GC).not_to receive(:start)
77
+
78
+ context "when current rss is over max rss" do
79
+ subject{ described_class.new(max_rss: 2) }
80
+
81
+ before do
82
+ allow(subject).to receive(:current_rss).and_return(3)
83
+ end
84
+
85
+ it "should request shutdown" do
86
+ expect(subject).to receive(:request_shutdown)
37
87
  subject.call(worker, job, queue){}
38
88
  end
39
- end
40
- context "but max rss is 0" do
41
- subject{ described_class.new(max_rss: 0) }
42
- it "should not request shutdown" do
43
- expect(subject).to_not receive(:request_shutdown)
89
+
90
+ it "should call garbage collect" do
91
+ allow(subject).to receive(:request_shutdown)
92
+ expect(GC).to receive(:start).with(full_mark: true, immediate_sweep: true)
44
93
  subject.call(worker, job, queue){}
45
94
  end
46
- end
47
- end
48
- end
49
95
 
50
- describe "#request_shutdown" do
51
- context "grace time is default" do
52
- before { allow(subject).to receive(:shutdown){ sleep 0.01 } }
53
- it "should call shutdown" do
54
- expect(subject).to receive(:shutdown)
55
- subject.send(:request_shutdown).join
56
- end
57
- it "should not call shutdown twice when called concurrently" do
58
- expect(subject).to receive(:shutdown).once
59
- 2.times.map{ subject.send(:request_shutdown) }.each(&:join)
96
+ context "and skip_shutdown_if is given" do
97
+ subject{ described_class.new(max_rss: 2, skip_shutdown_if: skip_shutdown_proc) }
98
+
99
+ context "and skip_shutdown_if is a proc" do
100
+ let(:skip_shutdown_proc) { proc { |worker| true } }
101
+ it "should NOT request shutdown" do
102
+ expect(subject).not_to receive(:request_shutdown)
103
+ subject.call(worker, job, queue){}
104
+ end
105
+ end
106
+
107
+ context "and skip_shutdown_if is a lambda" do
108
+ let(:skip_shutdown_proc) { ->(worker, job, queue) { true } }
109
+ it "should NOT request shutdown" do
110
+ expect(subject).not_to receive(:request_shutdown)
111
+ subject.call(worker, job, queue){}
112
+ end
113
+ end
114
+
115
+ context "and skip_shutdown_if returns false" do
116
+ let(:skip_shutdown_proc) { proc { |worker, job, queue| false } }
117
+ it "should still request shutdown" do
118
+ expect(subject).to receive(:request_shutdown)
119
+ subject.call(worker, job, queue){}
120
+ end
121
+ end
122
+
123
+ context "and skip_shutdown_if returns nil" do
124
+ let(:skip_shutdown_proc) { proc { |worker, job, queue| nil } }
125
+ it "should still request shutdown" do
126
+ expect(subject).to receive(:request_shutdown)
127
+ subject.call(worker, job, queue){}
128
+ end
129
+ end
130
+ end
131
+
132
+ context "when gc is false" do
133
+ subject{ described_class.new(max_rss: 2, gc: false) }
134
+ it "should not call garbage collect" do
135
+ allow(subject).to receive(:request_shutdown)
136
+ expect(GC).not_to receive(:start)
137
+ subject.call(worker, job, queue){}
138
+ end
139
+ end
140
+
141
+ context "but max rss is 0" do
142
+ subject{ described_class.new(max_rss: 0) }
143
+ it "should not request shutdown" do
144
+ expect(subject).to_not receive(:request_shutdown)
145
+ subject.call(worker, job, queue){}
146
+ end
147
+ end
60
148
  end
61
149
  end
62
150
 
63
- context "grace time is 5 seconds" do
64
- subject{ described_class.new(max_rss: 2, grace_time: 5.0, shutdown_wait: 0) }
65
- it "should wait the specified grace time before calling shutdown" do
66
- # there are busy jobs that will not terminate within the grace time
67
- allow(subject).to receive(:no_jobs_on_quiet_processes?).and_return(false)
68
-
69
- shutdown_request_time = nil
70
- shutdown_time = nil
71
-
72
- # replace the original #request_shutdown to track
73
- # when the shutdown is requested
74
- original_request_shutdown = subject.method(:request_shutdown)
75
- allow(subject).to receive(:request_shutdown) do
76
- shutdown_request_time= Time.now
77
- original_request_shutdown.call
151
+ describe "#request_shutdown" do
152
+ context "grace time is default" do
153
+ before { allow(subject).to receive(:shutdown){ sleep 0.01 } }
154
+ it "should call shutdown" do
155
+ expect(subject).to receive(:shutdown)
156
+ subject.send(:request_shutdown).join
78
157
  end
79
-
80
- # track when the SIGTERM signal is sent
81
- allow(Process).to receive(:kill) do |*args|
82
- shutdown_time = Time.now if args[0] == 'SIGTERM'
158
+ it "should not call shutdown twice when called concurrently" do
159
+ expect(subject).to receive(:shutdown).once
160
+ 2.times.map{ subject.send(:request_shutdown) }.each(&:join)
83
161
  end
162
+ end
84
163
 
85
- allow(subject).to receive(:pid).and_return(99)
164
+ context "grace time is 5 seconds" do
165
+ subject{ described_class.new(max_rss: 2, grace_time: 5.0, shutdown_wait: 0) }
166
+ it "should wait the specified grace time before calling shutdown" do
167
+ # there are busy jobs that will not terminate within the grace time
168
+ allow(subject).to receive(:no_jobs_on_quiet_processes?).and_return(false)
86
169
 
87
- subject.send(:request_shutdown).join
170
+ shutdown_request_time = nil
171
+ shutdown_time = nil
88
172
 
89
- elapsed_time = shutdown_time - shutdown_request_time
173
+ # replace the original #request_shutdown to track
174
+ # when the shutdown is requested
175
+ original_request_shutdown = subject.method(:request_shutdown)
176
+ allow(subject).to receive(:request_shutdown) do
177
+ shutdown_request_time= Time.now
178
+ original_request_shutdown.call
179
+ end
90
180
 
91
- # the elapsed time beetween shutdown request and the actual
92
- # shutdown signal should be greater than the specificed grace_time
93
- expect(elapsed_time).to be >= 5.0
181
+ # track when the process has been required to stop
182
+ expect(sidekiq_process).to receive(:stop!) do |*args|
183
+ shutdown_time = Time.now
184
+ end
185
+
186
+ allow(Process).to receive(:kill)
187
+ allow(Process).to receive(:pid).and_return(99)
188
+
189
+ subject.send(:request_shutdown).join
190
+
191
+ elapsed_time = shutdown_time - shutdown_request_time
192
+
193
+ # the elapsed time between shutdown request and the actual
194
+ # shutdown signal should be greater than the specified grace_time
195
+ expect(elapsed_time).to be >= 5.0
196
+ end
94
197
  end
95
- end
96
198
 
97
- context "grace time is Float::INFINITY" do
98
- subject{ described_class.new(max_rss: 2, grace_time: Float::INFINITY, shutdown_wait: 0) }
99
- it "call signal only on jobs" do
100
- allow(subject).to receive(:no_jobs_on_quiet_processes?).and_return(true)
101
- allow(subject).to receive(:pid).and_return(99)
102
- expect(Process).to receive(:kill).with('TSTP', 99)
103
- expect(Process).to receive(:kill).with('SIGTERM', 99)
104
- expect(Process).to receive(:kill).with('SIGKILL', 99)
199
+ context "grace time is Float::INFINITY" do
200
+ subject{ described_class.new(max_rss: 2, grace_time: Float::INFINITY, shutdown_wait: 0) }
201
+ it "call signal only on jobs" do
202
+ allow(subject).to receive(:jobs_finished?).and_return(true)
203
+ allow(Process).to receive(:pid).and_return(99)
204
+ expect(sidekiq_process).to receive(:quiet!)
205
+ expect(sidekiq_process).to receive(:stop!)
206
+ expect(Process).to receive(:kill).with('SIGKILL', 99)
105
207
 
106
- subject.send(:request_shutdown).join
208
+ subject.send(:request_shutdown).join
209
+ end
107
210
  end
108
211
  end
109
212
  end
110
213
 
111
- describe "#quiet_signal" do
112
- it "should give TSTP if Sidekiq version is > 5.0" do
113
- stub_const("Sidekiq::VERSION", "5.0")
114
- expect(subject.send :quiet_signal).to eq "TSTP"
115
- stub_const("Sidekiq::VERSION", "5.2.1")
116
- expect(subject.send :quiet_signal).to eq "TSTP"
117
- end
118
- it "should give USR1 if Sidekiq version is < 5.0" do
119
- stub_const("Sidekiq::VERSION", "3.0")
120
- expect(subject.send :quiet_signal).to eq "USR1"
121
- stub_const("Sidekiq::VERSION", "4.6.7")
122
- expect(subject.send :quiet_signal).to eq "USR1"
123
- end
214
+ def rspec_info(msg)
215
+ is_printing_progress = RSpec.configuration.formatters.any? { |f| /ProgressFormatter/.match?(f.class.name) }
216
+ return if is_printing_progress
217
+ RSpec.configuration.reporter.message msg
124
218
  end
125
219
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sidekiq-worker-killer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cyrille Courtiere
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-05-26 00:00:00.000000000 Z
11
+ date: 2022-09-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: get_process_mem
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '3'
33
+ version: '5'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '3'
40
+ version: '5'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: 0.49.1
69
+ - !ruby/object:Gem::Dependency
70
+ name: appraisal
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
69
83
  description:
70
84
  email:
71
85
  - dev@klaxit.com
@@ -96,8 +110,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
96
110
  - !ruby/object:Gem::Version
97
111
  version: '0'
98
112
  requirements: []
99
- rubyforge_project:
100
- rubygems_version: 2.5.2.3
113
+ rubygems_version: 3.0.3
101
114
  signing_key:
102
115
  specification_version: 4
103
116
  summary: Sidekiq worker killer