Hello community,
here is the log from the commit of package rubygem-puma_worker_killer for
openSUSE:Factory checked in at 2017-06-08 15:01:32
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/rubygem-puma_worker_killer (Old)
and /work/SRC/openSUSE:Factory/.rubygem-puma_worker_killer.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "rubygem-puma_worker_killer"
Thu Jun 8 15:01:32 2017 rev:3 rq:497708 version:0.1.0
Changes:
--------
---
/work/SRC/openSUSE:Factory/rubygem-puma_worker_killer/rubygem-puma_worker_killer.changes
2016-11-07 12:23:16.000000000 +0100
+++
/work/SRC/openSUSE:Factory/.rubygem-puma_worker_killer.new/rubygem-puma_worker_killer.changes
2017-06-08 15:01:33.419268918 +0200
@@ -1,0 +2,10 @@
+Tue May 23 10:11:52 UTC 2017 - [email protected]
+
+- updated to version 0.1.0
+ see installed CHANGELOG.md
+
+ ## 0.1.0
+
+ - Emit extra data via `pre_term` callback before puma worker killer
terminates a worker #49.
+
+-------------------------------------------------------------------
Old:
----
puma_worker_killer-0.0.7.gem
New:
----
puma_worker_killer-0.1.0.gem
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ rubygem-puma_worker_killer.spec ++++++
--- /var/tmp/diff_new_pack.vzaGLb/_old 2017-06-08 15:01:34.147166190 +0200
+++ /var/tmp/diff_new_pack.vzaGLb/_new 2017-06-08 15:01:34.147166190 +0200
@@ -1,7 +1,7 @@
#
# spec file for package rubygem-puma_worker_killer
#
-# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany.
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -24,7 +24,7 @@
#
Name: rubygem-puma_worker_killer
-Version: 0.0.7
+Version: 0.1.0
Release: 0
%define mod_name puma_worker_killer
%define mod_full_name %{mod_name}-%{version}
++++++ puma_worker_killer-0.0.7.gem -> puma_worker_killer-0.1.0.gem ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/CHANGELOG.md new/CHANGELOG.md
--- old/CHANGELOG.md 2016-10-13 16:56:01.000000000 +0200
+++ new/CHANGELOG.md 2017-05-12 17:28:39.000000000 +0200
@@ -1,3 +1,7 @@
+## 0.1.0
+
+- Emit extra data via `pre_term` callback before puma worker killer terminates
a worker #49.
+
## 0.0.7
- Logging is configurable #41
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/README.md new/README.md
--- old/README.md 2016-10-13 16:56:01.000000000 +0200
+++ new/README.md 2017-05-12 17:28:39.000000000 +0200
@@ -34,6 +34,8 @@
A rolling restart will kill each of your workers on a rolling basis. You set
the frequency which it conducts the restart. This is a simple way to keep
memory down as Ruby web programs generally increase memory usage over time. If
you're using Heroku [it is difficult to measure RAM from inside of a container
accurately](https://github.com/schneems/get_process_mem/issues/7), so it is
recommended to use this feature or use a [log-drain-based worker
killer](https://github.com/arches/whacamole). You can enable roling restarts by
running:
```ruby
+# config/puma.rb
+
before_fork do
require 'puma_worker_killer'
@@ -103,10 +105,30 @@
config.rolling_restart_frequency = 12 * 3600 # 12 hours in seconds
config.reaper_status_logs = true # setting this to false will not log lines
like:
# PumaWorkerKiller: Consuming 54.34765625 mb with master and 2 workers.
+
+ config.pre_term = -> (worker) { puts "Worker #{worker.inspect} being killed"
}
end
PumaWorkerKiller.start
```
+### pre_term
+
+`config.pre_term` will be called just prior to worker termination with the
worker that is about to be terminated. This may be useful to use in keeping
track of metrics, time of day workers are restarted, etc.
+
+By default Puma Worker Killer will emit a log when a worker is being killed
+
+```
+PumaWorkerKiller: Out of memory. 5 workers consuming total: 500 mb out of max:
450 mb. Sending TERM to pid 23 consuming 53 mb.
+```
+
+or
+
+```
+PumaWorkerKiller: Rolling Restart. 5 workers consuming total: 650mb mb.
Sending TERM to pid 34.
+```
+
+However you may want to collect more data, such as sending an event to an
error collection service like rollbar or airbrake. The `pre_term` lambda gets
called before any worker is killed by PWK for any reason.
+
## Attention
If you start puma as a daemon, to add puma worker killer config into puma
config file, rather than into initializers:
Binary files old/checksums.yaml.gz and new/checksums.yaml.gz differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/lib/puma_worker_killer/puma_memory.rb
new/lib/puma_worker_killer/puma_memory.rb
--- old/lib/puma_worker_killer/puma_memory.rb 2016-10-13 16:56:01.000000000
+0200
+++ new/lib/puma_worker_killer/puma_memory.rb 2017-05-12 17:28:39.000000000
+0200
@@ -12,6 +12,10 @@
workers.size
end
+ def term_worker(worker)
+ worker.term
+ end
+
def term_largest_worker
largest_worker.term
# Process.wait(largest_worker.pid)
@@ -78,4 +82,4 @@
end
end
end
-end
\ No newline at end of file
+end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/lib/puma_worker_killer/reaper.rb
new/lib/puma_worker_killer/reaper.rb
--- old/lib/puma_worker_killer/reaper.rb 2016-10-13 16:56:01.000000000
+0200
+++ new/lib/puma_worker_killer/reaper.rb 2017-05-12 17:28:39.000000000
+0200
@@ -1,9 +1,10 @@
module PumaWorkerKiller
class Reaper
- def initialize(max_ram, master = nil, reaper_status_logs = true)
+ def initialize(max_ram, master = nil, reaper_status_logs = true, pre_term)
@cluster = PumaWorkerKiller::PumaMemory.new(master)
@max_ram = max_ram
@reaper_status_logs = reaper_status_logs
+ @pre_term = pre_term
end
# used for tes
@@ -15,7 +16,18 @@
return false if @cluster.workers_stopped?
if (total = get_total_memory) > @max_ram
@cluster.master.log "PumaWorkerKiller: Out of memory.
#{@cluster.workers.count} workers consuming total: #{total} mb out of max:
#{@max_ram} mb. Sending TERM to pid #{@cluster.largest_worker.pid} consuming
#{@cluster.largest_worker_memory} mb."
- @cluster.term_largest_worker
+
+ # Fetch the largest_worker so that both `@pre_term` and `term_worker`
are called with the same worker
+ # Avoids a race condition where:
+ # Worker A consume 100 mb memory
+ # Worker B consume 99 mb memory
+ # pre_term gets called with Worker A
+ # A new request comes in, Worker B takes it, and consumes 101 mb
memory
+ # term_largest_worker (previously here) gets called and terms Worker
B (thus not passing the about-to-be-terminated worker to `@pre_term`)
+ largest_worker = @cluster.largest_worker
+ @pre_term.call(largest_worker)
+ @cluster.term_worker(largest_worker)
+
elsif @reaper_status_logs
@cluster.master.log "PumaWorkerKiller: Consuming #{total} mb with
master and #{@cluster.workers.count} workers."
end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/lib/puma_worker_killer/rolling_restart.rb
new/lib/puma_worker_killer/rolling_restart.rb
--- old/lib/puma_worker_killer/rolling_restart.rb 2016-10-13
16:56:01.000000000 +0200
+++ new/lib/puma_worker_killer/rolling_restart.rb 2017-05-12
17:28:39.000000000 +0200
@@ -12,7 +12,7 @@
def reap(wait_between_worker_kill = 60) # seconds
return false unless @cluster.running?
@cluster.workers.each do |worker, ram|
- @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 pid #{worker.pid}."
+ @cluster.master.log "PumaWorkerKiller: Rolling Restart.
#{@cluster.workers.count} workers consuming total: #{ get_total_memory } mb.
Sending TERM to pid #{worker.pid}."
worker.term
sleep wait_between_worker_kill
end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/lib/puma_worker_killer/version.rb
new/lib/puma_worker_killer/version.rb
--- old/lib/puma_worker_killer/version.rb 2016-10-13 16:56:01.000000000
+0200
+++ new/lib/puma_worker_killer/version.rb 2017-05-12 17:28:39.000000000
+0200
@@ -1,3 +1,3 @@
module PumaWorkerKiller
- VERSION = "0.0.7"
+ VERSION = "0.1.0"
end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/lib/puma_worker_killer.rb
new/lib/puma_worker_killer.rb
--- old/lib/puma_worker_killer.rb 2016-10-13 16:56:01.000000000 +0200
+++ new/lib/puma_worker_killer.rb 2017-05-12 17:28:39.000000000 +0200
@@ -3,19 +3,20 @@
module PumaWorkerKiller
extend self
- attr_accessor :ram, :frequency, :percent_usage, :rolling_restart_frequency,
:reaper_status_logs
+ attr_accessor :ram, :frequency, :percent_usage, :rolling_restart_frequency,
:reaper_status_logs, :pre_term
self.ram = 512 # mb
self.frequency = 10 # seconds
self.percent_usage = 0.99 # percent of RAM to use
self.rolling_restart_frequency = 6 * 3600 # 6 hours in seconds
self.reaper_status_logs = true
+ self.pre_term = lambda { |_| } # nop
def config
yield self
end
- def reaper(ram = self.ram, percent = self.percent_usage, reaper_status_logs
= self.reaper_status_logs)
- Reaper.new(ram * percent_usage, nil, reaper_status_logs)
+ def reaper(ram = self.ram, percent = self.percent_usage, reaper_status_logs
= self.reaper_status_logs, pre_term = self.pre_term)
+ Reaper.new(ram * percent_usage, nil, reaper_status_logs, pre_term)
end
def start(frequency = self.frequency, reaper = self.reaper)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/metadata new/metadata
--- old/metadata 2016-10-13 16:56:01.000000000 +0200
+++ new/metadata 2017-05-12 17:28:39.000000000 +0200
@@ -1,14 +1,14 @@
--- !ruby/object:Gem::Specification
name: puma_worker_killer
version: !ruby/object:Gem::Version
- version: 0.0.7
+ version: 0.1.0
platform: ruby
authors:
- Richard Schneeman
autorequire:
bindir: bin
cert_chain: []
-date: 2016-10-13 00:00:00.000000000 Z
+date: 2017-05-12 00:00:00.000000000 Z
dependencies:
- !ruby/object:Gem::Dependency
name: puma
@@ -124,6 +124,7 @@
- test/fixtures/config/puma_worker_killer_start.rb
- test/fixtures/default.ru
- test/fixtures/fixture_helper.rb
+- test/fixtures/pre_term.ru
- test/fixtures/rolling_restart.ru
- test/puma_worker_killer_test.rb
- test/test_helper.rb
@@ -147,7 +148,7 @@
version: '0'
requirements: []
rubyforge_project:
-rubygems_version: 2.6.4
+rubygems_version: 2.6.11
signing_key:
specification_version: 4
summary: If you have a memory leak in your web code puma_worker_killer can
keep it
@@ -157,7 +158,7 @@
- test/fixtures/config/puma_worker_killer_start.rb
- test/fixtures/default.ru
- test/fixtures/fixture_helper.rb
+- test/fixtures/pre_term.ru
- test/fixtures/rolling_restart.ru
- test/puma_worker_killer_test.rb
- test/test_helper.rb
-has_rdoc:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/test/fixtures/pre_term.ru
new/test/fixtures/pre_term.ru
--- old/test/fixtures/pre_term.ru 1970-01-01 01:00:00.000000000 +0100
+++ new/test/fixtures/pre_term.ru 2017-05-12 17:28:39.000000000 +0200
@@ -0,0 +1,8 @@
+load File.expand_path("../fixture_helper.rb", __FILE__)
+
+PumaWorkerKiller.config do |config|
+ config.pre_term = lambda { |worker| puts("About to terminate worker:
#{worker.inspect}") }
+end
+PumaWorkerKiller.start
+
+run HelloWorldApp
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/test/puma_worker_killer_test.rb
new/test/puma_worker_killer_test.rb
--- old/test/puma_worker_killer_test.rb 2016-10-13 16:56:01.000000000 +0200
+++ new/test/puma_worker_killer_test.rb 2017-05-12 17:28:39.000000000 +0200
@@ -33,6 +33,18 @@
end
end
+ def test_pre_term
+ file = fixture_path.join("pre_term.ru")
+ port = 0
+ command = "bundle exec puma #{ file } -t 1:1 -w 2 --preload --debug -p #{
port }"
+ options = { wait_for: "booted", timeout: 5, env: { "PUMA_FREQUENCY" => 1,
'PUMA_RAM' => 1} }
+
+ WaitForIt.new(command, options) do |spawn|
+ assert_contains(spawn, "Out of memory")
+ assert_contains(spawn, "About to terminate worker:") # defined in
pre_term.ru
+ end
+ end
+
def assert_contains(spawn, string)
assert spawn.wait(string), "Expected logs to contain '#{string}' but it
did not, contents: #{ spawn.log.read }"
end
@@ -50,4 +62,3 @@
end
end
end
-