worker_killer 1.0.2.187852 → 1.0.3.189564

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
2
  SHA256:
3
- metadata.gz: 0cde26e5d9705270605884443084f3dada5182e12ce9cba38c91ef5206837ced
4
- data.tar.gz: 8ebe3a9edafa87bafb84edd1f52277bb62dc9db7484fa4f0515ec0acaaf5d9ac
3
+ metadata.gz: 8de386a9112f6941110e0cc8f75d2276c859ca36d9cff4e5eadfb39dd33013fe
4
+ data.tar.gz: 7a1f7f3b042a3603db7e0a51a30cdb99f872bfb1288d8545c1b893241a1118f8
5
5
  SHA512:
6
- metadata.gz: 8bb89c7851d4dd6a127fa33273ca6c64e899c1d03d7e44709435a940944e7dff074a2f56f794221790464836d174fbb2dfa02f1ee08cf333a4b05342c6b0e1d7
7
- data.tar.gz: ca33356f8884b182c7ad06883b337168b563f105829f5f587471b87972d76b3738e97f5bb7e6cbcfe335d630cf386cb2026d805eb1ff1a264d60961ae5d27735
6
+ metadata.gz: a6397322a93eb40332f728b0b0bf5114aec40571f76ee3a6a64b1125be8fa7d9221f3158be4b1960fcd8c28b26cebe2b500cb582ebee39876414a881e709a0ed
7
+ data.tar.gz: 39bafdacf68392a4c1c05ac5b600d821a7e3cd368acbe3b585d855b1527e08b3898c53b17f458a74207c0987c2d93e9689302ce5c1a3b0d4b5c9138e8a382a67
@@ -24,11 +24,12 @@ module WorkerKiller
24
24
  def configure_lifecycle(lifecycle)
25
25
  # Count condition after every job
26
26
  lifecycle.after(:perform) do |worker, *_args|
27
- @time_to_burn = limiter.check
27
+ @time_to_burn ||= limiter.check
28
28
  end
29
29
 
30
30
  # Stop execution only after whole loop completed
31
31
  lifecycle.after(:loop) do |worker, *_args|
32
+ @time_to_burn ||= limiter.check
32
33
  reaction.call(limiter, killer, worker) if @time_to_burn
33
34
  end
34
35
  end
@@ -5,36 +5,57 @@ module WorkerKiller
5
5
 
6
6
  attr_reader :min, :max, :limit, :started_at, :check_cycle
7
7
 
8
- def initialize(min: (1024**3), max: (2 * (1024**3)), check_cycle: 16, verbose: false)
9
- @min = min
10
- @max = max
11
- @limit = @min + WorkerKiller.randomize(@max - @min + 1)
8
+ def initialize(min:, max:, check_cycle: 16, verbose: false)
9
+ if min
10
+ # set static memory limits
11
+ @min = min
12
+ @max = max
13
+ @limit = @min + WorkerKiller.randomize(@max - @min + 1)
14
+ @limit_mb = (@limit / 1024 / 1024).round(1)
15
+ else
16
+ # prepare for relative memory limits
17
+ @max_percent = max
18
+ end
19
+
12
20
  @check_cycle = check_cycle
13
21
  @check_count = 0
14
22
  @verbose = verbose
15
23
  end
16
24
 
17
25
  def check
18
- return nil if @limit <= 1024**2
19
-
20
26
  @started_at ||= Time.now
21
27
  @check_count += 1
22
28
 
23
29
  return nil if (@check_count % @check_cycle) != 0
24
30
 
25
31
  rss = GetProcessMem.new.bytes
32
+ # initialize relative memory limits on first check
33
+ set_limits(rss, rss + rss * @max_percent) if min.nil?
34
+
35
+ do_check(rss)
36
+ end
37
+
38
+ def do_check(rss)
39
+ rss_mb = (rss / 1024 / 1024).round(1)
40
+
26
41
  if @verbose
27
- logger.info "#{self.class}: worker (pid: #{Process.pid}) using #{rss} bytes(#{rss / 1024 / 1024}mb)."
42
+ logger.info "#{self.class}: worker (pid: #{Process.pid}) using #{rss_mb} MB (of #{@limit_mb} MB)"
28
43
  end
29
44
  @check_count = 0
30
45
 
31
46
  return false if rss <= @limit
32
47
 
33
- logger.warn "#{self.class}: worker (pid: #{Process.pid}) exceeds memory limit (#{rss} bytes > #{@limit} bytes)"
48
+ logger.warn "#{self.class}: worker (pid: #{Process.pid}) exceeds memory limit (#{rss_mb} MB > #{@limit_mb} MB)"
34
49
 
35
50
  true
36
51
  end
37
52
 
53
+ def set_limits(min, max)
54
+ @min = min
55
+ @limit = @max = max
56
+ @limit_mb = (@limit / 1024 / 1024).round(1)
57
+ end
58
+
38
59
  def logger
39
60
  WorkerKiller.configuration.logger
40
61
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module WorkerKiller
4
4
 
5
- VERSION = '1.0.2'
5
+ VERSION = '1.0.3'
6
6
 
7
7
  end
8
8
 
@@ -1,13 +1,12 @@
1
1
  RSpec.describe WorkerKiller::DelayedJobPlugin::JobsLimiter do
2
-
3
- let(:killer) {double}
2
+ let(:killer) { double }
4
3
  subject(:plugin){ described_class.new(killer: killer) }
5
4
 
6
5
  context 'DelayedJob initialization' do
7
6
  let(:lifecycle) { double }
8
7
  subject(:instance) { plugin.new(lifecycle) }
9
-
10
- it do
8
+
9
+ it do
11
10
  expect(lifecycle).to receive(:after).with(:perform).and_yield
12
11
  expect(lifecycle).to receive(:after).with(:loop).and_yield
13
12
  instance
@@ -1,13 +1,12 @@
1
1
  RSpec.describe WorkerKiller::DelayedJobPlugin::OOMLimiter do
2
-
3
- let(:killer) {double}
4
- subject(:plugin){ described_class.new(killer: killer) }
2
+ let(:killer) { double }
3
+ subject(:plugin){ described_class.new(min: (1024**3), max: (2 * (1024**3)), killer: killer) }
5
4
 
6
5
  context 'DelayedJob initialization' do
7
6
  let(:lifecycle) { double }
8
7
  subject(:instance) { plugin.new(lifecycle) }
9
-
10
- it do
8
+
9
+ it do
11
10
  expect(lifecycle).to receive(:after).with(:perform).and_yield
12
11
  expect(lifecycle).to receive(:after).with(:loop).and_yield
13
12
  instance
@@ -2,13 +2,10 @@ RSpec.describe WorkerKiller::MemoryLimiter do
2
2
  let(:logger){ Logger.new(nil) }
3
3
 
4
4
  subject{ described_class.new(**options) }
5
- let(:mb){ 1024 * 1024 }
6
- let(:min){ rand(50..100) * mb }
7
- let(:max){ min + rand(100) * mb }
8
5
  let(:check_cycle){ 5 }
9
- let(:options){ { min: min, max: max, check_cycle: check_cycle, verbose: true} }
6
+ let(:options){ { min: min, max: max, check_cycle: check_cycle, verbose: true } }
7
+ let(:memory) { instance_double(GetProcessMem) }
10
8
 
11
- it { is_expected.to have_attributes(min: min, max: max, limit: a_value_between(min, max)) }
12
9
 
13
10
  def skip_cycles(object, cycles)
14
11
  (cycles - 1).times do
@@ -16,28 +13,68 @@ RSpec.describe WorkerKiller::MemoryLimiter do
16
13
  end
17
14
  end
18
15
 
19
- it 'expect to skip check while less than cycle count' do
20
- expect(GetProcessMem).not_to receive(:new)
21
-
22
- skip_cycles(subject, check_cycle)
16
+ before do
17
+ allow(GetProcessMem).to receive(:new).and_return(memory)
23
18
  end
24
19
 
25
- it 'expect to skip check after cycle count reached' do
26
- memory = instance_double(GetProcessMem)
27
- expect(memory).to receive(:bytes).and_return(min - 1)
28
- expect(GetProcessMem).to receive(:new).and_return(memory)
20
+ context 'fixed memory limit' do
21
+ let(:mb){ 1024 * 1024 }
22
+ let(:min){ rand(50..100) * mb }
23
+ let(:max){ min + rand(100) * mb }
24
+
25
+ it { is_expected.to have_attributes(min: min, max: max, limit: a_value_between(min, max)) }
26
+
27
+ it 'expect to skip check while less than cycle count' do
28
+ expect(GetProcessMem).not_to receive(:new)
29
+
30
+ skip_cycles(subject, check_cycle)
31
+ end
32
+
33
+ it 'expect to skip check after cycle count reached' do
34
+ expect(memory).to receive(:bytes).and_return(min - 1)
35
+
36
+ skip_cycles(subject, check_cycle)
37
+ expect(subject.check).to be_falsey
38
+ end
29
39
 
30
- skip_cycles(subject, check_cycle)
31
- expect(subject.check).to be_falsey
40
+ it 'expect call reaction when check succeded' do
41
+ expect(memory).to receive(:bytes).and_return(subject.limit + 1)
42
+
43
+ skip_cycles(subject, check_cycle)
44
+ expect(subject.check).to be_truthy
45
+ end
32
46
  end
33
47
 
34
- it 'expect call reaction when check succeded' do
35
- memory = instance_double(GetProcessMem)
36
- expect(memory).to receive(:bytes).and_return(subject.limit + 1)
37
- expect(GetProcessMem).to receive(:new).and_return(memory)
48
+ context 'relative memory limit' do
49
+ let(:min){ nil }
50
+ let(:max){ 0.5 }
51
+ let(:rss) { 100 * 1024 * 1024 }
52
+ let(:min_expected) { rss }
53
+ let(:max_expected) { min_expected + min_expected * max }
38
54
 
39
- skip_cycles(subject, check_cycle)
40
- expect(subject.check).to be_truthy
55
+ it { is_expected.to have_attributes(min: nil, max: nil, limit: nil) }
56
+
57
+ it 'expect to initialize limits on first check' do
58
+ expect(memory).to receive(:bytes).and_return(rss)
59
+
60
+ skip_cycles(subject, check_cycle)
61
+ is_expected.to have_attributes(min: nil, max: nil, limit: nil)
62
+
63
+ expect(subject.check).to be_falsey
64
+
65
+ is_expected.to have_attributes(min: min_expected, max: max_expected, limit: max_expected)
66
+ end
67
+
68
+ it 'expect call reaction when check succeded' do
69
+ expect(memory).to receive(:bytes).and_return(rss)
70
+
71
+ skip_cycles(subject, check_cycle)
72
+ expect(subject.check).to be_falsey
73
+
74
+ expect(memory).to receive(:bytes).and_return(subject.limit + 1)
75
+ skip_cycles(subject, check_cycle)
76
+ expect(subject.check).to be_truthy
77
+ end
41
78
  end
42
79
  end
43
80
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: worker_killer
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2.187852
4
+ version: 1.0.3.189564
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samoilenko Yuri
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-09-28 00:00:00.000000000 Z
11
+ date: 2023-10-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: get_process_mem
@@ -171,15 +171,15 @@ signing_key:
171
171
  specification_version: 4
172
172
  summary: Kill any workers by memory and request counts or take custom reaction
173
173
  test_files:
174
- - spec/middleware_spec.rb
174
+ - spec/killer/signal_spec.rb
175
+ - spec/killer/delayed_job_spec.rb
176
+ - spec/killer/passenger_spec.rb
175
177
  - spec/killer_spec.rb
178
+ - spec/count_limiter_spec.rb
179
+ - spec/worker_killer_spec.rb
180
+ - spec/support/logger.rb
181
+ - spec/middleware_spec.rb
176
182
  - spec/spec_helper.rb
177
183
  - spec/delayed_job_plugin/oom_limiter_spec.rb
178
184
  - spec/delayed_job_plugin/jobs_limiter_spec.rb
179
- - spec/killer/passenger_spec.rb
180
- - spec/killer/signal_spec.rb
181
- - spec/killer/delayed_job_spec.rb
182
185
  - spec/memory_limiter_spec.rb
183
- - spec/support/logger.rb
184
- - spec/worker_killer_spec.rb
185
- - spec/count_limiter_spec.rb