From 51547d99fc7047cd602d57301381625d777ece2f Mon Sep 17 00:00:00 2001 From: Jonathan Clem Date: Tue, 12 Mar 2013 15:43:38 -0700 Subject: [PATCH] v0.4.0 Kill processes from a thread --- AUTHORS | 1 + ChangeLog | 4 ++++ VERSION | 2 +- lib/unicorn/worker_killer.rb | 35 +++++++++++++++++++++++------------ unicorn-worker-killer.gemspec | 4 ++-- 5 files changed, 31 insertions(+), 15 deletions(-) diff --git a/AUTHORS b/AUTHORS index ba1bdad..203e03e 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,2 +1,3 @@ Kazuki Ohta Sadayuki FURUHASHI +Jonathan Clem diff --git a/ChangeLog b/ChangeLog index 667b292..3b4164e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +Release 0.4.0 - 2013/03/12 + * Send signals from inside a Thread (required for QUIT signal) + * Fix broken if/else in kill_self + Release 0.3.6 - 2013/03/09 * do not require configuration * fix missing randomize() in MaxRequests killer diff --git a/VERSION b/VERSION index 449d7e7..1d0ba9e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.3.6 +0.4.0 diff --git a/lib/unicorn/worker_killer.rb b/lib/unicorn/worker_killer.rb index a25032c..7f8229e 100644 --- a/lib/unicorn/worker_killer.rb +++ b/lib/unicorn/worker_killer.rb @@ -11,24 +11,31 @@ class << self # @see http://unicorn.bogomips.org/SIGNALS.html def self.kill_self(logger, start_time) alive_sec = (Time.now - start_time).to_i + worker_pid = Process.pid - i = 0 - while true - i += 1 - sig = :QUIT - if i > configuration.max_quit - sig = :TERM - elsif i > configuration.max_term - sig = :KILL - end + Thread.new do + i = 0 + + while pid_exist?(worker_pid) + i += 1 + + sig = :QUIT + sig = :TERM if i > configuration.max_quit + sig = :KILL if i > configuration.max_term - logger.warn "#{self} send SIG#{sig} (pid: #{Process.pid}) alive: #{alive_sec} sec (trial #{i})" - Process.kill sig, Process.pid + logger.warn "#{self} send SIG#{sig} (pid: #{worker_pid}) alive: #{alive_sec} sec (trial #{i})" + Process.kill sig, worker_pid - sleep configuration.sleep_interval + sleep configuration.sleep_interval + end end end + def self.pid_exist?(pid) + Process.getpgid(pid) + rescue Errno::ESRCH + end + module Oom # Killing the process must be occurred at the outside of the request. We're # using similar techniques used by OobGC, to ensure actual killing doesn't @@ -52,11 +59,13 @@ def randomize(integer) def process_client(client) super(client) # Unicorn::HttpServer#process_client + return if @_worker_memory_limit_min == 0 && @_worker_memory_limit_max == 0 @_worker_process_start ||= Time.now @_worker_memory_limit ||= @_worker_memory_limit_min + randomize(@_worker_memory_limit_max - @_worker_memory_limit_min + 1) @_worker_check_count += 1 + if @_worker_check_count % @_worker_check_cycle == 0 rss = _worker_rss() if rss > @_worker_memory_limit @@ -112,6 +121,7 @@ def self.new(app, max_requests_min = 3072, max_requests_max = 4096) s.instance_variable_set(:@_worker_max_requests_min, max_requests_min) s.instance_variable_set(:@_worker_max_requests_max, max_requests_max) end + app # pretend to be Rack middleware since it was in the past end @@ -126,6 +136,7 @@ def process_client(client) @_worker_process_start ||= Time.now @_worker_cur_requests ||= @_worker_max_requests_min + randomize(@_worker_max_requests_max - @_worker_max_requests_min + 1) @_worker_max_requests ||= @_worker_cur_requests + if (@_worker_cur_requests -= 1) <= 0 logger.warn "#{self}: worker (pid: #{Process.pid}) exceeds max number of requests (limit: #{@_worker_max_requests})" Unicorn::WorkerKiller.kill_self(logger, @_worker_process_start) diff --git a/unicorn-worker-killer.gemspec b/unicorn-worker-killer.gemspec index 0dac587..692f843 100644 --- a/unicorn-worker-killer.gemspec +++ b/unicorn-worker-killer.gemspec @@ -7,8 +7,8 @@ Gem::Specification.new do |gem| gem.homepage = "https://github.com/kzk/unicorn-worker-killer" gem.summary = gem.description gem.version = File.read("VERSION").strip - gem.authors = ["Kazuki Ohta", "Sadayuki Furuhashi"] - gem.email = ["kazuki.ohta@gmail.com", "frsyuki@gmail.com"] + gem.authors = ["Kazuki Ohta", "Sadayuki Furuhashi", "Jonathan Clem"] + gem.email = ["kazuki.ohta@gmail.com", "frsyuki@gmail.com", "jonathan@jclem.net"] gem.has_rdoc = false #gem.platform = Gem::Platform::RUBY gem.files = `git ls-files`.split("\n")