puma_worker_killer 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|