zombie_passenger_killer 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
data/Readme.md CHANGED
@@ -34,11 +34,13 @@ Usage
34
34
  ### Bluepill script
35
35
 
36
36
  app.process("zombie_passenger_killer") do |process|
37
- process.start_command = "zombie_passenger_killer --max 5 --history 10 --cpu 30 --interval 10 >> /var/log/autorotate/zombie_passenger_killer.log 2>&1"
37
+ process.start_command = "zombie_passenger_killer --max 5 --history 10 --cpu 30 --interval 10"
38
+ process.stdout = process.stderr = "/var/log/autorotate/zombie_passenger_killer.log"
38
39
  process.pid_file = "/var/run/zombie_passenger_killer.pid"
39
40
  process.daemonize = true
40
41
  end
41
42
 
43
+
42
44
  ### God script
43
45
 
44
46
  TODO
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.2
1
+ 0.1.3
@@ -1,6 +1,8 @@
1
1
  class ZombiePassengerKiller
2
2
  VERSION = File.read( File.join(File.dirname(__FILE__),'..','VERSION') ).strip
3
3
 
4
+ attr_accessor :out # overwriteable for tests
5
+
4
6
  def initialize(options)
5
7
  @history = {}
6
8
  @history_entries = options[:history] || 5
@@ -8,6 +10,8 @@ class ZombiePassengerKiller
8
10
  @high_cpu = options[:cpu] || 70
9
11
  @grace_time = options[:grace] || 5
10
12
  @pattern = options[:pattern] || ' Rack: '
13
+ @strace_time = 5
14
+ @out = STDOUT
11
15
  end
12
16
 
13
17
  def store_current_cpu(processes)
@@ -22,7 +26,8 @@ class ZombiePassengerKiller
22
26
  end
23
27
 
24
28
  def get_strace(pid, time)
25
- %x(timeout #{time} strace -p #{pid} 2>&1) if system("which timeout > /dev/null")
29
+ Process.getpgid(pid) rescue return 'No such process'
30
+ `( strace -p #{pid} 2>&1 ) & sleep #{time} ; kill $! 2>&1`
26
31
  end
27
32
 
28
33
  def hunt_zombies
@@ -57,10 +62,10 @@ class ZombiePassengerKiller
57
62
  end
58
63
 
59
64
  def kill_zombie(pid)
60
- puts "Killing passenger process #{pid}"
61
- puts get_strace(pid, 5)
62
- puts %x(kill #{pid})
65
+ @out.puts "Killing passenger process #{pid}"
66
+ @out.puts get_strace(pid, @strace_time)
67
+ Process.kill('TERM', pid) rescue nil
63
68
  sleep @grace_time
64
- %x(kill -9 #{pid})
69
+ Process.kill('KILL', pid) rescue nil
65
70
  end
66
71
  end
@@ -11,56 +11,127 @@ describe ZombiePassengerKiller do
11
11
  ZombiePassengerKiller::VERSION.should =~ /^\d+\.\d+\.\d+$/
12
12
  end
13
13
 
14
- it "does not kill anything by default" do
15
- killer.should_not_receive(:kill_zombie)
16
- killer.hunt_zombies
17
- end
14
+ describe "#hunt_zombies" do
15
+ it "does not kill anything by default" do
16
+ killer.should_not_receive(:kill_zombie)
17
+ killer.hunt_zombies
18
+ end
18
19
 
19
- it "kill zombies" do
20
- killer.stub!(:passenger_pids).and_return([123])
21
- killer.stub!(:process_status).and_return([{:pid => 124, :cpu => 0}])
22
- killer.should_receive(:kill_zombie).with(124)
23
- killer.hunt_zombies
24
- end
20
+ it "finds the right zombies" do
21
+ killer.stub!(:passenger_pids).and_return([123])
22
+ killer.stub!(:process_status).and_return([{:pid => 124, :cpu => 0}])
23
+ killer.should_receive(:kill_zombie).with(124)
24
+ killer.hunt_zombies
25
+ end
25
26
 
26
- it "kills zombies with high cpu over max" do
27
- @options = {:max => 1}
28
- killer.stub!(:process_status).and_return([{:pid => 111, :cpu => 100}])
29
- killer.should_receive(:kill_zombie).with(111)
30
- killer.hunt_zombies
31
- end
27
+ it "kills zombies with high cpu over max" do
28
+ @options = {:max => 1}
29
+ killer.stub!(:process_status).and_return([{:pid => 111, :cpu => 100}])
30
+ killer.should_receive(:kill_zombie).with(111)
31
+ killer.hunt_zombies
32
+ end
32
33
 
33
- it "does not kills zombies with high cpu under max" do
34
- @options = {:max => 2}
35
- killer.stub!(:process_status).and_return([{:pid => 111, :cpu => 100}])
36
- killer.should_not_receive(:kill_zombie).with(111)
37
- killer.hunt_zombies
38
- end
34
+ it "does not kills zombies with high cpu under max" do
35
+ @options = {:max => 2}
36
+ killer.stub!(:process_status).and_return([{:pid => 111, :cpu => 100}])
37
+ killer.should_not_receive(:kill_zombie).with(111)
38
+ killer.hunt_zombies
39
+ end
39
40
 
40
- it "ignores high cpu levels in old history" do
41
- @options = {:max => 2, :history => 2}
42
- killer.should_not_receive(:kill_zombie).with(111)
43
- killer.stub!(:process_status).and_return([{:pid => 111, :cpu => 100}])
44
- killer.hunt_zombies
45
- killer.stub!(:process_status).and_return([{:pid => 111, :cpu => 0}])
46
- killer.hunt_zombies
47
- killer.stub!(:process_status).and_return([{:pid => 111, :cpu => 100}])
48
- killer.hunt_zombies
49
- end
41
+ it "ignores high cpu levels in old history" do
42
+ @options = {:max => 2, :history => 2}
43
+ killer.should_not_receive(:kill_zombie).with(111)
44
+ killer.stub!(:process_status).and_return([{:pid => 111, :cpu => 100}])
45
+ killer.hunt_zombies
46
+ killer.stub!(:process_status).and_return([{:pid => 111, :cpu => 0}])
47
+ killer.hunt_zombies
48
+ killer.stub!(:process_status).and_return([{:pid => 111, :cpu => 100}])
49
+ killer.hunt_zombies
50
+ end
50
51
 
51
- it "kills on high cpu levels in recent history" do
52
- @options = {:max => 2, :history => 2}
53
- killer.stub!(:process_status).and_return([{:pid => 111, :cpu => 100}])
54
- killer.hunt_zombies
55
- killer.should_receive(:kill_zombie).with(111)
56
- killer.hunt_zombies
52
+ it "kills on high cpu levels in recent history" do
53
+ @options = {:max => 2, :history => 2}
54
+ killer.stub!(:process_status).and_return([{:pid => 111, :cpu => 100}])
55
+ killer.hunt_zombies
56
+ killer.should_receive(:kill_zombie).with(111)
57
+ killer.hunt_zombies
58
+ end
57
59
  end
58
60
 
59
- it "prints its version" do
60
- `./bin/zombie_passenger_killer -v`.should =~ /^\d+\.\d+\.\d+$/m
61
+ describe "#kill_zombies" do
62
+ before do
63
+ killer.out = StringIO.new
64
+ killer.instance_eval{
65
+ @grace_time = 0.1
66
+ @strace_time = 0.1
67
+ }
68
+ end
69
+
70
+ def pid_of(marker)
71
+ processes = `ps -ef | grep '#{marker}' | grep -v grep`
72
+ processes.strip.split("\n").last.split(/\s+/)[1].to_i
73
+ end
74
+
75
+ def start_bogus_process(options={})
76
+ marker = "TEST---#{rand(999999999999)}"
77
+ Thread.new do
78
+ `ruby -e 'at_exit{ puts "proper exit"; #{'sleep 10' if options[:hang]}}; sleep 10; puts "#{marker}"' 2>&1`
79
+ end
80
+ sleep 1 # give process time to spin up
81
+ pid_of(marker)
82
+ end
83
+
84
+ def process_alive?(pid)
85
+ Process.getpgid(pid)
86
+ rescue Errno::ESRCH
87
+ false
88
+ end
89
+
90
+ def output
91
+ killer.out.rewind
92
+ killer.out.read
93
+ end
94
+
95
+ it "kills normal processes" do
96
+ pid = start_bogus_process
97
+ lambda{
98
+ killer.kill_zombie(pid)
99
+ sleep 0.1
100
+ }.should change{ process_alive?(pid) }
101
+ end
102
+
103
+ it "kills hanging processes" do
104
+ pid = start_bogus_process :hang => true
105
+ lambda{
106
+ killer.kill_zombie(pid)
107
+ sleep 0.1
108
+ }.should change{ process_alive?(pid) }
109
+ end
110
+
111
+ it "prints an strace of the process" do
112
+ pid = start_bogus_process
113
+ killer.kill_zombie(pid)
114
+ output.should include('attach:')
115
+ end
116
+
117
+ it "does not take a strace of a dead process" do
118
+ killer.kill_zombie(111)
119
+ output.should_not include('attach:')
120
+ end
121
+
122
+ it "does not fail with an unknown pid" do
123
+ killer.kill_zombie(111)
124
+ output.should include('No such process')
125
+ end
61
126
  end
62
127
 
63
- it "prints help" do
64
- `./bin/zombie_passenger_killer -h`.should include('Usage')
128
+ describe "cli" do
129
+ it "prints its version" do
130
+ `./bin/zombie_passenger_killer -v`.should =~ /^\d+\.\d+\.\d+$/m
131
+ end
132
+
133
+ it "prints help" do
134
+ `./bin/zombie_passenger_killer -h`.should include('Usage')
135
+ end
65
136
  end
66
137
  end
@@ -4,14 +4,13 @@
4
4
  # -*- encoding: utf-8 -*-
5
5
 
6
6
  Gem::Specification.new do |s|
7
- s.name = %q{zombie_passenger_killer}
8
- s.version = "0.1.2"
7
+ s.name = "zombie_passenger_killer"
8
+ s.version = "0.1.3"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Michael Grosser"]
12
- s.date = %q{2011-09-09}
13
- s.default_executable = %q{zombie_passenger_killer}
14
- s.email = %q{michael@grosser.it}
12
+ s.date = "2012-01-05"
13
+ s.email = "michael@grosser.it"
15
14
  s.executables = ["zombie_passenger_killer"]
16
15
  s.files = [
17
16
  "Gemfile",
@@ -25,10 +24,10 @@ Gem::Specification.new do |s|
25
24
  "spec/zombie_passenger_killer_spec.rb",
26
25
  "zombie_passenger_killer.gemspec"
27
26
  ]
28
- s.homepage = %q{http://github.com/grosser/zombie_passenger_killer}
27
+ s.homepage = "http://github.com/grosser/zombie_passenger_killer"
29
28
  s.require_paths = ["lib"]
30
- s.rubygems_version = %q{1.6.2}
31
- s.summary = %q{Guaranteed zombie passengers death}
29
+ s.rubygems_version = "1.8.10"
30
+ s.summary = "Guaranteed zombie passengers death"
32
31
 
33
32
  if s.respond_to? :specification_version then
34
33
  s.specification_version = 3
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: 31
4
+ hash: 29
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 1
9
- - 2
10
- version: 0.1.2
9
+ - 3
10
+ version: 0.1.3
11
11
  platform: ruby
12
12
  authors:
13
13
  - Michael Grosser
@@ -15,8 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-09-09 00:00:00 +02:00
19
- default_executable: zombie_passenger_killer
18
+ date: 2012-01-05 00:00:00 Z
20
19
  dependencies: []
21
20
 
22
21
  description:
@@ -38,7 +37,6 @@ files:
38
37
  - spec/spec_helper.rb
39
38
  - spec/zombie_passenger_killer_spec.rb
40
39
  - zombie_passenger_killer.gemspec
41
- has_rdoc: true
42
40
  homepage: http://github.com/grosser/zombie_passenger_killer
43
41
  licenses: []
44
42
 
@@ -68,7 +66,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
68
66
  requirements: []
69
67
 
70
68
  rubyforge_project:
71
- rubygems_version: 1.6.2
69
+ rubygems_version: 1.8.10
72
70
  signing_key:
73
71
  specification_version: 3
74
72
  summary: Guaranteed zombie passengers death