puma_worker_killer 0.0.3 → 0.0.4
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 +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +32 -1
- data/lib/puma_worker_killer.rb +10 -2
- data/lib/puma_worker_killer/auto_reap.rb +1 -1
- data/lib/puma_worker_killer/rolling_restart.rb +21 -0
- data/lib/puma_worker_killer/version.rb +1 -1
- data/puma_worker_killer.gemspec +3 -1
- data/test/fixtures/app.ru +2 -0
- data/test/puma_worker_killer_test.rb +18 -3
- metadata +20 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 48de7bd76c24b540567047c78701abd668b5a8d1
|
4
|
+
data.tar.gz: 66ecc21b98a516a97e533325008a4ccbb8cf7b14
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dbcf620657fe6b2f04c0904da89bba0f739f3ce30dcbc50cabc668e8664e97a6d4bfa756da1f9fa6f571c25cc79d1dd31f408ea3e78bd70cfca81a72d3411df7
|
7
|
+
data.tar.gz: a464e3a896491affbbc724a6ba32919b6027353fe03de1397eb226b9b777fb768a58cd191ee9a7334cad3f8854fa5b21c9a05a6fa7bbbea684210aa31e03e391
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -9,6 +9,8 @@ If you have a memory leak in your code, finding and plugging it can be a hercule
|
|
9
9
|
|
10
10
|
Puma worker killer can only function if you have enabled cluster mode or hybrid mode (threads + worker cluster). If you are only using threads (and not workers) then puma worker killer cannot help keep your memory in control.
|
11
11
|
|
12
|
+
BTW restarting your processes to controll memory is like putting a bandaid on a gunshot wound, try figuring out the reason you're seeing so much memory bloat [derailed benchmarks](https://github.com/schneems/derailed_benchmarks) can help.
|
13
|
+
|
12
14
|
|
13
15
|
## Install
|
14
16
|
|
@@ -20,13 +22,17 @@ gem 'puma_worker_killer'
|
|
20
22
|
|
21
23
|
Then run `$ bundle install`
|
22
24
|
|
25
|
+
<!--
|
23
26
|
## Use
|
24
27
|
|
25
28
|
> If you like `puma_worker_killer` consider using [puma_auto_tune instead](https://github.com/schneems/puma_auto_tune). It handles memory leaks and tunes your workers too!
|
26
29
|
|
30
|
+
-->
|
31
|
+
|
27
32
|
Somewhere in your main process run this code:
|
28
33
|
|
29
34
|
```ruby
|
35
|
+
# config/initializers/puma_worker_killer.rb
|
30
36
|
PumaWorkerKiller.start
|
31
37
|
```
|
32
38
|
|
@@ -41,7 +47,9 @@ PumaWorkerKiller.config do |config|
|
|
41
47
|
config.ram = 1024 # mb
|
42
48
|
config.frequency = 5 # seconds
|
43
49
|
config.percent_usage = 0.98
|
50
|
+
config.rolling_restart_frequency = 12 * 3600 # 12 hours in seconds
|
44
51
|
end
|
52
|
+
PumaWorkerKiller.start
|
45
53
|
```
|
46
54
|
|
47
55
|
It is important that you tell your code how much RAM is available on your system. The default is 512 mb (the same size as a Heroku 1x dyno). You can change this value like this:
|
@@ -62,6 +70,29 @@ You may want to tune the worker killer to run more or less often. You can adjust
|
|
62
70
|
PumaWorkerKiller.frequency = 20 # seconds
|
63
71
|
```
|
64
72
|
|
73
|
+
You may want to periodically restart all of your workers rather than simply killing your largest. To do that set:
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
PumaWorkerKiller.rolling_restart_frequency = 12 * 3600 # 12 hours in seconds
|
77
|
+
```
|
78
|
+
|
79
|
+
By default PumaWorkerKiller will perform a rolling restart of all your worker processes every 12 hours. To disable, set to `false`.
|
80
|
+
|
81
|
+
## Only turn on Rolling Restarts
|
82
|
+
|
83
|
+
If you're running on a platform like [Heroku where it is difficult to measure RAM from inside of a container accurately](https://github.com/schneems/get_process_mem/issues/7), you may want to disable the "worker killer" functionality and only use the rolling restart. You can do that by running:
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
PumaWorkerKiller.enable_rolling_restart
|
87
|
+
```
|
88
|
+
|
89
|
+
or you can pass in the restart frequency
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
PumaWorkerKiller.enable_rolling_restart(12 * 3600) # 12 hours in seconds
|
93
|
+
```
|
94
|
+
|
95
|
+
Make sure if you do this to not accidentally call `PumaWorkerKiller.start` as well.
|
65
96
|
|
66
97
|
## License
|
67
98
|
|
@@ -70,4 +101,4 @@ MIT
|
|
70
101
|
|
71
102
|
## Feedback
|
72
103
|
|
73
|
-
Open up an issue or ping me on twitter [@schneems](http://twitter.com/schneems).
|
104
|
+
Open up an issue or ping me on twitter [@schneems](http://twitter.com/schneems).
|
data/lib/puma_worker_killer.rb
CHANGED
@@ -3,10 +3,11 @@ require 'get_process_mem'
|
|
3
3
|
module PumaWorkerKiller
|
4
4
|
extend self
|
5
5
|
|
6
|
-
attr_accessor :ram, :frequency, :percent_usage
|
6
|
+
attr_accessor :ram, :frequency, :percent_usage, :rolling_restart_frequency
|
7
7
|
self.ram = 512 # mb
|
8
8
|
self.frequency = 10 # seconds
|
9
9
|
self.percent_usage = 0.99 # percent of RAM to use
|
10
|
+
self.rolling_restart_frequency = 6 * 3600
|
10
11
|
|
11
12
|
def config
|
12
13
|
yield self
|
@@ -18,10 +19,17 @@ module PumaWorkerKiller
|
|
18
19
|
|
19
20
|
def start(frequency = self.frequency, reaper = self.reaper)
|
20
21
|
AutoReap.new(frequency, reaper).start
|
22
|
+
enable_rolling_restart(rolling_restart_frequency) if rolling_restart_frequency
|
23
|
+
end
|
24
|
+
|
25
|
+
def enable_rolling_restart(frequency = self.rolling_restart_frequency)
|
26
|
+
frequency = frequency + rand(0..10.0) # so all workers don't restart at the exact same time across multiple machines
|
27
|
+
AutoReap.new(frequency, RollingRestart.new).start
|
21
28
|
end
|
22
29
|
end
|
23
30
|
|
24
31
|
require 'puma_worker_killer/puma_memory'
|
25
32
|
require 'puma_worker_killer/reaper'
|
33
|
+
require 'puma_worker_killer/rolling_restart'
|
26
34
|
require 'puma_worker_killer/auto_reap'
|
27
|
-
require 'puma_worker_killer/version'
|
35
|
+
require 'puma_worker_killer/version'
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module PumaWorkerKiller
|
2
|
+
class RollingRestart
|
3
|
+
def initialize(master = nil)
|
4
|
+
@cluster = PumaWorkerKiller::PumaMemory.new(master)
|
5
|
+
end
|
6
|
+
|
7
|
+
# used for tes
|
8
|
+
def get_total_memory
|
9
|
+
@cluster.get_total_memory
|
10
|
+
end
|
11
|
+
|
12
|
+
def reap(wait_between_worker_kill = 60) # seconds
|
13
|
+
return false unless @cluster.running?
|
14
|
+
@cluster.workers.each do |worker, ram|
|
15
|
+
@cluster.master.log "PumaWorkerKiller: Rolling Restart. #{@cluster.workers.count} workers consuming total: #{ get_total_memory } mb out of max: #{@max_ram} mb. Sending TERM to #{worker.inspect}"
|
16
|
+
worker.term
|
17
|
+
sleep wait_between_worker_kill
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/puma_worker_killer.gemspec
CHANGED
@@ -19,6 +19,8 @@ Gem::Specification.new do |gem|
|
|
19
19
|
gem.require_paths = ["lib"]
|
20
20
|
|
21
21
|
gem.add_dependency "puma", "~> 2.7"
|
22
|
-
gem.add_dependency "get_process_mem", "~> 0.
|
22
|
+
gem.add_dependency "get_process_mem", "~> 0.2"
|
23
23
|
gem.add_development_dependency "rake", "~> 10.1"
|
24
|
+
gem.add_development_dependency "test-unit", ">= 0"
|
25
|
+
|
24
26
|
end
|
data/test/fixtures/app.ru
CHANGED
@@ -5,12 +5,12 @@ class PumaWorkerKillerTest < Test::Unit::TestCase
|
|
5
5
|
def test_starts
|
6
6
|
app_path = fixture_path.join("app.ru")
|
7
7
|
port = 0 # http://stackoverflow.com/questions/200484/how-do-you-find-a-free-tcp-server-port-using-ruby
|
8
|
-
puma_log = Pathname.new "puma.log"
|
9
|
-
|
10
|
-
pid = Process.spawn("PUMA_FREQUENCY=1 bundle exec puma #{app_path} -t 1:1 -w 5 --preload --debug -p #{port} > #{puma_log}")
|
8
|
+
puma_log = Pathname.new "#{ SecureRandom.hex }-puma.log"
|
9
|
+
pid = Process.spawn("PUMA_FREQUENCY=1 bundle exec puma #{ app_path } -t 1:1 -w 5 --preload --debug -p #{ port } > #{puma_log}")
|
11
10
|
sleep 5
|
12
11
|
assert_match "PumaWorkerKiller:", puma_log.read
|
13
12
|
ensure
|
13
|
+
puma_log.delete
|
14
14
|
Process.kill('TERM', pid) if pid
|
15
15
|
end
|
16
16
|
|
@@ -59,4 +59,19 @@ class PumaWorkerKillerTest < Test::Unit::TestCase
|
|
59
59
|
cluster.workers.map(&:term)
|
60
60
|
end
|
61
61
|
|
62
|
+
|
63
|
+
def test_rolling_restart
|
64
|
+
ram = rand(75..100) #mb
|
65
|
+
cluster = FakeCluster.new
|
66
|
+
cluster.add_worker
|
67
|
+
|
68
|
+
worker = cluster.workers.first
|
69
|
+
reaper = PumaWorkerKiller::RollingRestart.new(cluster)
|
70
|
+
reaper.reap(1)
|
71
|
+
|
72
|
+
assert_equal 1, cluster.workers.select {|w| w.is_term? }.count
|
73
|
+
ensure
|
74
|
+
cluster.workers.map(&:term)
|
75
|
+
end
|
62
76
|
end
|
77
|
+
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: puma_worker_killer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Richard Schneeman
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-09-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: puma
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '0.
|
33
|
+
version: '0.2'
|
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: '0.
|
40
|
+
version: '0.2'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rake
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '10.1'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: test-unit
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
55
69
|
description: " Kills pumas, the code kind "
|
56
70
|
email:
|
57
71
|
- richard.schneeman+rubygems@gmail.com
|
@@ -69,6 +83,7 @@ files:
|
|
69
83
|
- lib/puma_worker_killer/auto_reap.rb
|
70
84
|
- lib/puma_worker_killer/puma_memory.rb
|
71
85
|
- lib/puma_worker_killer/reaper.rb
|
86
|
+
- lib/puma_worker_killer/rolling_restart.rb
|
72
87
|
- lib/puma_worker_killer/version.rb
|
73
88
|
- puma_worker_killer.gemspec
|
74
89
|
- test/fixtures/app.ru
|
@@ -94,7 +109,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
94
109
|
version: '0'
|
95
110
|
requirements: []
|
96
111
|
rubyforge_project:
|
97
|
-
rubygems_version: 2.
|
112
|
+
rubygems_version: 2.4.5.1
|
98
113
|
signing_key:
|
99
114
|
specification_version: 4
|
100
115
|
summary: If you have a memory leak in your web code puma_worker_killer can keep it
|