zombie_passenger_killer 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -1,7 +1,7 @@
1
1
  source :rubygems
2
+ gemspec
2
3
 
3
- group :dev do # not development <-> would add unneeded development dependencies in gemspec
4
+ group :development do
4
5
  gem 'rake'
5
6
  gem 'rspec', '~>2'
6
- gem 'jeweler'
7
7
  end
data/Gemfile.lock CHANGED
@@ -1,12 +1,12 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ zombie_passenger_killer (0.2.0)
5
+
1
6
  GEM
2
7
  remote: http://rubygems.org/
3
8
  specs:
4
9
  diff-lcs (1.1.3)
5
- git (1.2.5)
6
- jeweler (1.6.4)
7
- bundler (~> 1.0)
8
- git (>= 1.2.5)
9
- rake
10
10
  rake (0.9.2)
11
11
  rspec (2.6.0)
12
12
  rspec-core (~> 2.6.0)
@@ -21,6 +21,6 @@ PLATFORMS
21
21
  ruby
22
22
 
23
23
  DEPENDENCIES
24
- jeweler
25
24
  rake
26
25
  rspec (~> 2)
26
+ zombie_passenger_killer!
data/Rakefile CHANGED
@@ -1,18 +1,21 @@
1
+ require 'bundler/gem_tasks'
2
+
1
3
  task :default do
2
4
  sh "rspec spec/"
3
5
  end
4
6
 
5
- begin
6
- require 'jeweler'
7
- Jeweler::Tasks.new do |gem|
8
- gem.name = 'zombie_passenger_killer'
9
- gem.summary = "Guaranteed zombie passengers death"
10
- gem.email = "michael@grosser.it"
11
- gem.homepage = "http://github.com/grosser/#{gem.name}"
12
- gem.authors = ["Michael Grosser"]
13
- end
7
+ rule /^version:bump:.*/ do |t|
8
+ sh "git status | grep 'nothing to commit'" # ensure we are not dirty
9
+ index = ['major', 'minor','patch'].index(t.name.split(':').last)
10
+ file = 'lib/zombie_passenger_killer/version.rb'
11
+
12
+ version_file = File.read(file)
13
+ old_version, *version_parts = version_file.match(/(\d+)\.(\d+)\.(\d+)/).to_a
14
+ version_parts[index] = version_parts[index].to_i + 1
15
+ version_parts[2] = 0 if index < 2 # remove patch for minor
16
+ version_parts[1] = 0 if index < 1 # remove minor for major
17
+ new_version = version_parts * '.'
18
+ File.open(file,'w'){|f| f.write(version_file.sub(old_version, new_version)) }
14
19
 
15
- Jeweler::GemcutterTasks.new
16
- rescue LoadError
17
- puts "Jeweler, or one of its dependencies, is not available. Install it with: gem install jeweler"
20
+ sh "bundle && git add #{file} Gemfile.lock && git commit -m 'bump version to #{new_version}'"
18
21
  end
data/Readme.md CHANGED
@@ -43,14 +43,14 @@ Usage
43
43
 
44
44
  ### God script
45
45
 
46
- TODO
47
-
46
+ # TODO
48
47
 
49
48
  Author
50
49
  ======
51
50
 
52
51
  ###Contributors
53
- - [mindreframer](https://github.com/mindreframer)
52
+ - [Roman Heinrich](https://github.com/mindreframer)
53
+ - [Kevin Mullin](https://github.com/kmullin)
54
54
 
55
55
  [Michael Grosser](http://grosser.it)<br/>
56
56
  michael@grosser.it<br/>
@@ -1,14 +1,9 @@
1
1
  #!/usr/bin/env ruby
2
- require 'rubygems'
3
2
  require 'optparse'
4
3
 
5
4
  $LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
6
5
  require 'zombie_passenger_killer'
7
6
 
8
- unless system("which timeout > /dev/null")
9
- warn "Please install timeout commandline tool e.g. via apt-get install timeout / apt-get install coreutils"
10
- end
11
-
12
7
  options = {}
13
8
  OptionParser.new do |opts|
14
9
  opts.banner = <<BANNER
@@ -32,8 +27,9 @@ end.parse!
32
27
  $stdout.sync = true
33
28
  puts "Started at #{Time.now}"
34
29
 
35
- killer = ZombiePassengerKiller.new(options)
30
+ killer = ZombiePassengerKiller::Reaper.new(options)
36
31
 
32
+ $0 = File.basename(__FILE__)
37
33
  loop do
38
34
  killer.hunt_zombies
39
35
  sleep options[:interval] || 10
@@ -0,0 +1,75 @@
1
+ module ZombiePassengerKiller
2
+ class Reaper
3
+
4
+ attr_accessor :out # overwriteable for tests
5
+
6
+ def initialize(options)
7
+ @history = {}
8
+ @history_entries = options[:history] || 5
9
+ @max_high_cpu = options[:max]
10
+ @high_cpu = options[:cpu] || 70
11
+ @grace_time = options[:grace] || 5
12
+ @pattern = options[:pattern] || ' Rack: '
13
+ @strace_time = 5
14
+ @out = STDOUT
15
+ end
16
+
17
+ def store_current_cpu(processes)
18
+ keys_to_remove = @history.keys - processes.map{|x| x[:pid] }
19
+ keys_to_remove.each{|k| !@history.delete k }
20
+
21
+ processes.each do |process|
22
+ @history[process[:pid]] ||= []
23
+ @history[process[:pid]] << process[:cpu]
24
+ @history[process[:pid]] = @history[process[:pid]].last(@history_entries)
25
+ end
26
+ end
27
+
28
+ def get_strace(pid, time)
29
+ Process.getpgid(pid) rescue return 'No such process'
30
+ `( strace -p #{pid} 2>&1 ) & sleep #{time} ; kill $! 2>&1`
31
+ end
32
+
33
+ def hunt_zombies
34
+ active_pids_in_passenger_status = passenger_pids
35
+ active_processes_in_processlist = process_status
36
+ zombies = active_processes_in_processlist.map{|x| x[:pid] } - active_pids_in_passenger_status rescue Array.new
37
+
38
+ # kill processes with high CPU if user wants it
39
+ high_load = if @max_high_cpu
40
+ store_current_cpu active_processes_in_processlist
41
+ active_pids_in_passenger_status.select do |pid|
42
+ @history[pid].count{|x| x > @high_cpu } >= @max_high_cpu
43
+ end
44
+ else
45
+ []
46
+ end
47
+
48
+ (high_load + zombies).each do |pid|
49
+ kill_zombie pid
50
+ end
51
+ end
52
+
53
+ # return array of pids reported from passenger-status command, nil if passenger-status doesn't run
54
+ def passenger_pids
55
+ pids = %x(passenger-status|grep PID).split("\n").map { |x| x.strip.match(/PID: \d*/).to_s.split[1].to_i }
56
+ pids if $?.exitstatus.zero?
57
+ end
58
+
59
+ def process_status
60
+ %x(ps -eo pid,pcpu,args|grep -v grep|grep '#{@pattern}').split("\n").map do |line|
61
+ values = line.strip.split[0..1]
62
+ {:pid => values.first.to_i, :cpu => values.last.to_f}
63
+ end
64
+ end
65
+
66
+ def kill_zombie(pid)
67
+ @out.puts "Killing passenger process #{pid}"
68
+ @out.puts get_strace(pid, @strace_time)
69
+ Process.kill('TERM', pid) rescue nil
70
+ sleep @grace_time # wait for it to die
71
+ Process.kill('KILL', pid) rescue nil
72
+ end
73
+
74
+ end
75
+ end
@@ -0,0 +1,3 @@
1
+ module ZombiePassengerKiller
2
+ Version = VERSION = '0.2.0'
3
+ end
@@ -1,71 +1,4 @@
1
- class ZombiePassengerKiller
2
- VERSION = File.read( File.join(File.dirname(__FILE__),'..','VERSION') ).strip
1
+ $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + '/../lib'))
3
2
 
4
- attr_accessor :out # overwriteable for tests
5
-
6
- def initialize(options)
7
- @history = {}
8
- @history_entries = options[:history] || 5
9
- @max_high_cpu = options[:max]
10
- @high_cpu = options[:cpu] || 70
11
- @grace_time = options[:grace] || 5
12
- @pattern = options[:pattern] || ' Rack: '
13
- @strace_time = 5
14
- @out = STDOUT
15
- end
16
-
17
- def store_current_cpu(processes)
18
- keys_to_remove = @history.keys - processes.map{|x| x[:pid] }
19
- keys_to_remove.each{|k| !@history.delete k }
20
-
21
- processes.each do |process|
22
- @history[process[:pid]] ||= []
23
- @history[process[:pid]] << process[:cpu]
24
- @history[process[:pid]] = @history[process[:pid]].last(@history_entries)
25
- end
26
- end
27
-
28
- def get_strace(pid, time)
29
- Process.getpgid(pid) rescue return 'No such process'
30
- `( strace -p #{pid} 2>&1 ) & sleep #{time} ; kill $! 2>&1`
31
- end
32
-
33
- def hunt_zombies
34
- active_pids_in_passenger_status = passenger_pids
35
- active_processes_in_processlist = process_status
36
- zombies = active_processes_in_processlist.map{|x| x[:pid] } - active_pids_in_passenger_status
37
-
38
- # kill processes with high CPU if user wants it
39
- high_load = if @max_high_cpu
40
- store_current_cpu active_processes_in_processlist
41
- active_pids_in_passenger_status.select do |pid|
42
- @history[pid].count{|x| x > @high_cpu } >= @max_high_cpu
43
- end
44
- else
45
- []
46
- end
47
-
48
- (high_load + zombies).each do |pid|
49
- kill_zombie pid
50
- end
51
- end
52
-
53
- def passenger_pids
54
- %x(passenger-status|grep PID).split("\n").map{|x| x.strip.match(/PID: \d*/).to_s.split[1]}.map(&:to_i)
55
- end
56
-
57
- def process_status
58
- %x(ps -eo pid,pcpu,args|grep -v grep|grep '#{@pattern}').split("\n").map do |line|
59
- values = line.strip.split[0..1]
60
- {:pid => values.first.to_i, :cpu => values.last.to_f}
61
- end
62
- end
63
-
64
- def kill_zombie(pid)
65
- @out.puts "Killing passenger process #{pid}"
66
- @out.puts get_strace(pid, @strace_time)
67
- Process.kill('TERM', pid) rescue nil
68
- sleep @grace_time
69
- Process.kill('KILL', pid) rescue nil
70
- end
71
- end
3
+ require 'zombie_passenger_killer/version'
4
+ require 'zombie_passenger_killer/reaper'
@@ -2,7 +2,7 @@ require File.expand_path('spec/spec_helper')
2
2
 
3
3
  describe ZombiePassengerKiller do
4
4
  let(:killer){
5
- k = ZombiePassengerKiller.new(@options || {})
5
+ k = ZombiePassengerKiller::Reaper.new(@options || {})
6
6
  k.stub!(:passenger_pids).and_return([111])
7
7
  k
8
8
  }
@@ -1,41 +1,12 @@
1
- # Generated by jeweler
2
- # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
- # -*- encoding: utf-8 -*-
1
+ $LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
2
+ require 'zombie_passenger_killer/version'
5
3
 
6
- Gem::Specification.new do |s|
7
- s.name = "zombie_passenger_killer"
8
- s.version = "0.1.3"
9
-
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
4
+ Gem::Specification.new "zombie_passenger_killer", ZombiePassengerKiller::VERSION do |s|
5
+ s.summary = "Guaranteed zombie passengers death"
11
6
  s.authors = ["Michael Grosser"]
12
- s.date = "2012-01-05"
13
7
  s.email = "michael@grosser.it"
14
- s.executables = ["zombie_passenger_killer"]
15
- s.files = [
16
- "Gemfile",
17
- "Gemfile.lock",
18
- "Rakefile",
19
- "Readme.md",
20
- "VERSION",
21
- "bin/zombie_passenger_killer",
22
- "lib/zombie_passenger_killer.rb",
23
- "spec/spec_helper.rb",
24
- "spec/zombie_passenger_killer_spec.rb",
25
- "zombie_passenger_killer.gemspec"
26
- ]
27
8
  s.homepage = "http://github.com/grosser/zombie_passenger_killer"
28
- s.require_paths = ["lib"]
29
- s.rubygems_version = "1.8.10"
30
- s.summary = "Guaranteed zombie passengers death"
31
-
32
- if s.respond_to? :specification_version then
33
- s.specification_version = 3
34
-
35
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
36
- else
37
- end
38
- else
39
- end
9
+ s.files = `git ls-files`.split("\n")
10
+ s.executables = ["zombie_passenger_killer"]
11
+ s.license = "MIT"
40
12
  end
41
-
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zombie_passenger_killer
3
3
  version: !ruby/object:Gem::Version
4
- hash: 29
4
+ hash: 23
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 1
9
- - 3
10
- version: 0.1.3
8
+ - 2
9
+ - 0
10
+ version: 0.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Michael Grosser
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-01-05 00:00:00 Z
18
+ date: 2012-02-09 00:00:00 Z
19
19
  dependencies: []
20
20
 
21
21
  description:
@@ -31,15 +31,16 @@ files:
31
31
  - Gemfile.lock
32
32
  - Rakefile
33
33
  - Readme.md
34
- - VERSION
35
34
  - bin/zombie_passenger_killer
36
35
  - lib/zombie_passenger_killer.rb
36
+ - lib/zombie_passenger_killer/reaper.rb
37
+ - lib/zombie_passenger_killer/version.rb
37
38
  - spec/spec_helper.rb
38
39
  - spec/zombie_passenger_killer_spec.rb
39
40
  - zombie_passenger_killer.gemspec
40
41
  homepage: http://github.com/grosser/zombie_passenger_killer
41
- licenses: []
42
-
42
+ licenses:
43
+ - MIT
43
44
  post_install_message:
44
45
  rdoc_options: []
45
46
 
@@ -66,7 +67,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
66
67
  requirements: []
67
68
 
68
69
  rubyforge_project:
69
- rubygems_version: 1.8.10
70
+ rubygems_version: 1.8.15
70
71
  signing_key:
71
72
  specification_version: 3
72
73
  summary: Guaranteed zombie passengers death
data/VERSION DELETED
@@ -1 +0,0 @@
1
- 0.1.3