puma_worker_killer 0.0.2 → 0.0.4

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
  SHA1:
3
- metadata.gz: 52f6ead7a78bc887408c2a249b3aed913fe90129
4
- data.tar.gz: 752ef55b46747f29aa84b92d84d0d72496fe315a
3
+ metadata.gz: 48de7bd76c24b540567047c78701abd668b5a8d1
4
+ data.tar.gz: 66ecc21b98a516a97e533325008a4ccbb8cf7b14
5
5
  SHA512:
6
- metadata.gz: 2c12b64d3108e5c4921dba09eb832edbfc008edfeade7cae4ca77429aea1da1dfcbe7fe49f37ac3ac2b5048ebf947e555cc45b352ca6e0303acf8fa9ed38705c
7
- data.tar.gz: 99ef751d60702d8ffd5d5eb83d8cb6fc22e5d4174d5fc3cba199bcec5b48dd46c3c80c7eb0682ab7708e484add4957d819656bb3d7742ceac30d59c3e92e14ea
6
+ metadata.gz: dbcf620657fe6b2f04c0904da89bba0f739f3ce30dcbc50cabc668e8664e97a6d4bfa756da1f9fa6f571c25cc79d1dd31f408ea3e78bd70cfca81a72d3411df7
7
+ data.tar.gz: a464e3a896491affbbc724a6ba32919b6027353fe03de1397eb226b9b777fb768a58cd191ee9a7334cad3f8854fa5b21c9a05a6fa7bbbea684210aa31e03e391
@@ -0,0 +1,7 @@
1
+ ## 0.0.4
2
+
3
+ - Add ability to do rolling restart
4
+
5
+ ## 0.0.3
6
+
7
+ - Fix memory metrics in on linux
data/README.md CHANGED
@@ -5,7 +5,11 @@
5
5
 
6
6
  ## What
7
7
 
8
- If you have a memory leak in your code, finding and plugging it can be a herculean effort. Instead what if you just killed your processes when they got to be too large? The Puma Worker Killer does just that. Similar to [Unicorn Worker Killer](https://github.com/kzk/unicorn-worker-killer) but for the Puma web server. Note that Puma can uses threads or processes to add concurrency, the Puma Worker Killer only helps if you are using clustered mode (concurrency via process).
8
+ If you have a memory leak in your code, finding and plugging it can be a herculean effort. Instead what if you just killed your processes when they got to be too large? The Puma Worker Killer does just that. Similar to [Unicorn Worker Killer](https://github.com/kzk/unicorn-worker-killer) but for the Puma web server.
9
+
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
+
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.
9
13
 
10
14
 
11
15
  ## Install
@@ -18,11 +22,17 @@ gem 'puma_worker_killer'
18
22
 
19
23
  Then run `$ bundle install`
20
24
 
25
+ <!--
21
26
  ## Use
22
27
 
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!
29
+
30
+ -->
31
+
23
32
  Somewhere in your main process run this code:
24
33
 
25
34
  ```ruby
35
+ # config/initializers/puma_worker_killer.rb
26
36
  PumaWorkerKiller.start
27
37
  ```
28
38
 
@@ -37,7 +47,9 @@ PumaWorkerKiller.config do |config|
37
47
  config.ram = 1024 # mb
38
48
  config.frequency = 5 # seconds
39
49
  config.percent_usage = 0.98
50
+ config.rolling_restart_frequency = 12 * 3600 # 12 hours in seconds
40
51
  end
52
+ PumaWorkerKiller.start
41
53
  ```
42
54
 
43
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:
@@ -58,6 +70,29 @@ You may want to tune the worker killer to run more or less often. You can adjust
58
70
  PumaWorkerKiller.frequency = 20 # seconds
59
71
  ```
60
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.
61
96
 
62
97
  ## License
63
98
 
@@ -66,4 +101,4 @@ MIT
66
101
 
67
102
  ## Feedback
68
103
 
69
- 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).
@@ -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'
@@ -18,4 +18,4 @@ module PumaWorkerKiller
18
18
  end
19
19
 
20
20
  end
21
- end
21
+ end
@@ -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
@@ -1,3 +1,3 @@
1
1
  module PumaWorkerKiller
2
- VERSION = "0.0.2"
3
- end
2
+ VERSION = "0.0.4"
3
+ end
@@ -18,7 +18,9 @@ Gem::Specification.new do |gem|
18
18
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
19
  gem.require_paths = ["lib"]
20
20
 
21
- gem.add_dependency "puma", "~> 2"
22
- gem.add_dependency "get_process_mem", "~> 0"
21
+ gem.add_dependency "puma", "~> 2.7"
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
@@ -10,6 +10,8 @@ end
10
10
  PumaWorkerKiller.start
11
11
 
12
12
 
13
+ puts "Frequency: #{PumaWorkerKiller.frequency}" if ENV['PUMA_FREQUENCY']
14
+
13
15
  class HelloWorld
14
16
  def response
15
17
  [200, {}, ['Hello World']]
@@ -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
- `rm #{puma_log}; touch #{puma_log}`
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.2
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: 2014-02-28 00:00:00.000000000 Z
11
+ date: 2015-09-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: puma
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '2'
19
+ version: '2.7'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '2'
26
+ version: '2.7'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: get_process_mem
29
29
  requirement: !ruby/object:Gem::Requirement
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
@@ -61,6 +75,7 @@ extra_rdoc_files: []
61
75
  files:
62
76
  - ".gitignore"
63
77
  - ".travis.yml"
78
+ - CHANGELOG.md
64
79
  - Gemfile
65
80
  - README.md
66
81
  - Rakefile
@@ -68,6 +83,7 @@ files:
68
83
  - lib/puma_worker_killer/auto_reap.rb
69
84
  - lib/puma_worker_killer/puma_memory.rb
70
85
  - lib/puma_worker_killer/reaper.rb
86
+ - lib/puma_worker_killer/rolling_restart.rb
71
87
  - lib/puma_worker_killer/version.rb
72
88
  - puma_worker_killer.gemspec
73
89
  - test/fixtures/app.ru
@@ -93,7 +109,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
93
109
  version: '0'
94
110
  requirements: []
95
111
  rubyforge_project:
96
- rubygems_version: 2.2.2
112
+ rubygems_version: 2.4.5.1
97
113
  signing_key:
98
114
  specification_version: 4
99
115
  summary: If you have a memory leak in your web code puma_worker_killer can keep it