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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ad7e53791affc61948522399fb84ff1695c15e10
4
- data.tar.gz: 1705c37b135041e88364c2f47ac6a59cceb6803d
3
+ metadata.gz: 48de7bd76c24b540567047c78701abd668b5a8d1
4
+ data.tar.gz: 66ecc21b98a516a97e533325008a4ccbb8cf7b14
5
5
  SHA512:
6
- metadata.gz: 14870594b03d9ec384b7f3bf6762c3d02f862b55d2ef5052db31578d9c8d852d2e08aaa46a4e277de5c68a210f634b416f3cc6a19ccefd09096dd325a625fc9a
7
- data.tar.gz: f6be7f6cb196854986b572f62a4ea606091ed59dda4bb0e8c045f5d25e0f8b33587e65906194eea3ac3a0690455bd9039e96df5f8b7b5068f74a1b0600769bce
6
+ metadata.gz: dbcf620657fe6b2f04c0904da89bba0f739f3ce30dcbc50cabc668e8664e97a6d4bfa756da1f9fa6f571c25cc79d1dd31f408ea3e78bd70cfca81a72d3411df7
7
+ data.tar.gz: a464e3a896491affbbc724a6ba32919b6027353fe03de1397eb226b9b777fb768a58cd191ee9a7334cad3f8854fa5b21c9a05a6fa7bbbea684210aa31e03e391
@@ -1,3 +1,7 @@
1
+ ## 0.0.4
2
+
3
+ - Add ability to do rolling restart
4
+
1
5
  ## 0.0.3
2
6
 
3
7
  - Fix memory metrics in on linux
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).
@@ -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.3"
2
+ VERSION = "0.0.4"
3
3
  end
@@ -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.1"
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.3
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-04-03 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
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '0.1'
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.1'
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.2.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