zombie_passenger_killer 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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