Permalink
Browse files

Fixed things on TODO list

  • Loading branch information...
2 parents b075ca0 + d7940db commit 868f940c72c46df57f9fb6c0f69a4f30901ffbae @kmullin kmullin committed Feb 9, 2012
View
@@ -1 +0,0 @@
-0.1.3
@@ -5,10 +5,6 @@ require 'optparse'
$LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
require 'zombie_passenger_killer'
-unless system("which timeout > /dev/null")
- warn "Please install timeout commandline tool e.g. via apt-get install timeout / apt-get install coreutils"
-end
-
options = {}
OptionParser.new do |opts|
opts.banner = <<BANNER
@@ -32,8 +28,9 @@ end.parse!
$stdout.sync = true
puts "Started at #{Time.now}"
-killer = ZombiePassengerKiller.new(options)
+killer = ZombiePassengerKiller::Reaper.new(options)
+$0 = File.basename(__FILE__)
loop do
killer.hunt_zombies
sleep options[:interval] || 10
@@ -1,71 +1,4 @@
-class ZombiePassengerKiller
- VERSION = File.read( File.join(File.dirname(__FILE__),'..','VERSION') ).strip
+$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + '/../lib'))
- attr_accessor :out # overwriteable for tests
-
- def initialize(options)
- @history = {}
- @history_entries = options[:history] || 5
- @max_high_cpu = options[:max]
- @high_cpu = options[:cpu] || 70
- @grace_time = options[:grace] || 5
- @pattern = options[:pattern] || ' Rack: '
- @strace_time = 5
- @out = STDOUT
- end
-
- def store_current_cpu(processes)
- keys_to_remove = @history.keys - processes.map{|x| x[:pid] }
- keys_to_remove.each{|k| !@history.delete k }
-
- processes.each do |process|
- @history[process[:pid]] ||= []
- @history[process[:pid]] << process[:cpu]
- @history[process[:pid]] = @history[process[:pid]].last(@history_entries)
- end
- end
-
- def get_strace(pid, time)
- Process.getpgid(pid) rescue return 'No such process'
- `( strace -p #{pid} 2>&1 ) & sleep #{time} ; kill $! 2>&1`
- end
-
- def hunt_zombies
- active_pids_in_passenger_status = passenger_pids
- active_processes_in_processlist = process_status
- zombies = active_processes_in_processlist.map{|x| x[:pid] } - active_pids_in_passenger_status
-
- # kill processes with high CPU if user wants it
- high_load = if @max_high_cpu
- store_current_cpu active_processes_in_processlist
- active_pids_in_passenger_status.select do |pid|
- @history[pid].count{|x| x > @high_cpu } >= @max_high_cpu
- end
- else
- []
- end
-
- (high_load + zombies).each do |pid|
- kill_zombie pid
- end
- end
-
- def passenger_pids
- %x(passenger-status|grep PID).split("\n").map{|x| x.strip.match(/PID: \d*/).to_s.split[1]}.map(&:to_i)
- end
-
- def process_status
- %x(ps -eo pid,pcpu,args|grep -v grep|grep '#{@pattern}').split("\n").map do |line|
- values = line.strip.split[0..1]
- {:pid => values.first.to_i, :cpu => values.last.to_f}
- end
- end
-
- def kill_zombie(pid)
- @out.puts "Killing passenger process #{pid}"
- @out.puts get_strace(pid, @strace_time)
- Process.kill('TERM', pid) rescue nil
- sleep @grace_time
- Process.kill('KILL', pid) rescue nil
- end
-end
+require 'zombie_passenger_killer/version'
+require 'zombie_passenger_killer/reaper'
@@ -0,0 +1,75 @@
+module ZombiePassengerKiller
+ class Reaper
+
+ attr_accessor :out # overwriteable for tests
+
+ def initialize(options)
+ @history = {}
+ @history_entries = options[:history] || 5
+ @max_high_cpu = options[:max]
+ @high_cpu = options[:cpu] || 70
+ @grace_time = options[:grace] || 5
+ @pattern = options[:pattern] || ' Rack: '
+ @strace_time = 5
+ @out = STDOUT
+ end
+
+ def store_current_cpu(processes)
+ keys_to_remove = @history.keys - processes.map{|x| x[:pid] }
+ keys_to_remove.each{|k| !@history.delete k }
+
+ processes.each do |process|
+ @history[process[:pid]] ||= []
+ @history[process[:pid]] << process[:cpu]
+ @history[process[:pid]] = @history[process[:pid]].last(@history_entries)
+ end
+ end
+
+ def get_strace(pid, time)
+ Process.getpgid(pid) rescue return 'No such process'
+ `( strace -p #{pid} 2>&1 ) & sleep #{time} ; kill $! 2>&1`
+ end
+
+ def hunt_zombies
+ active_pids_in_passenger_status = passenger_pids
+ active_processes_in_processlist = process_status
+ zombies = active_processes_in_processlist.map{|x| x[:pid] } - active_pids_in_passenger_status rescue Array.new
+
+ # kill processes with high CPU if user wants it
+ high_load = if @max_high_cpu
+ store_current_cpu active_processes_in_processlist
+ active_pids_in_passenger_status.select do |pid|
+ @history[pid].count{|x| x > @high_cpu } >= @max_high_cpu
+ end
+ else
+ []
+ end
+
+ (high_load + zombies).each do |pid|
+ kill_zombie pid
+ end
+ end
+
+ # return array of pids reported from passenger-status command, nil if passenger-status doesn't run
+ def passenger_pids
+ pids = %x(passenger-status|grep PID).split("\n").map { |x| x.strip.match(/PID: \d*/).to_s.split[1].to_i }
+ pids if $?.exitstatus.zero?
+ end
+
+ def process_status
+ %x(ps -eo pid,pcpu,args|grep -v grep|grep '#{@pattern}').split("\n").map do |line|
+ values = line.strip.split[0..1]
+ {:pid => values.first.to_i, :cpu => values.last.to_f}
+ end
+ end
+
+ def kill_zombie(pid)
+ @out.puts "Killing passenger process #{pid}"
+ @out.puts get_strace(pid, @strace_time)
+ Process.kill('TERM', pid) rescue nil
+ sleep @grace_time # wait for it to die
+ Process.kill('KILL', pid) rescue nil
+ end
+
+ end
+end
@@ -0,0 +1,3 @@
+module ZombiePassengerKiller
+ Version = VERSION = '0.1.3'
+end
@@ -2,7 +2,7 @@
describe ZombiePassengerKiller do
let(:killer){
- k = ZombiePassengerKiller.new(@options || {})
+ k = ZombiePassengerKiller::Reaper.new(@options || {})
k.stub!(:passenger_pids).and_return([111])
k
}
@@ -2,28 +2,22 @@
# DO NOT EDIT THIS FILE DIRECTLY
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
# -*- encoding: utf-8 -*-
+$:.push File.expand_path("../lib", __FILE__)
+require 'zombie_passenger_killer/version'
Gem::Specification.new do |s|
s.name = "zombie_passenger_killer"
- s.version = "0.1.3"
+ s.version = ZombiePassengerKiller::Version
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Michael Grosser"]
s.date = "2012-01-05"
s.email = "michael@grosser.it"
s.executables = ["zombie_passenger_killer"]
- s.files = [
- "Gemfile",
- "Gemfile.lock",
- "Rakefile",
- "Readme.md",
- "VERSION",
- "bin/zombie_passenger_killer",
- "lib/zombie_passenger_killer.rb",
- "spec/spec_helper.rb",
- "spec/zombie_passenger_killer_spec.rb",
- "zombie_passenger_killer.gemspec"
- ]
+ s.extra_rdoc_files = ["README.md"]
+
+ s.files = `git ls-files`.split("\n")
+ s.files -= ['.rvmrc', '.gitignore']
s.homepage = "http://github.com/grosser/zombie_passenger_killer"
s.require_paths = ["lib"]
s.rubygems_version = "1.8.10"

0 comments on commit 868f940

Please sign in to comment.