evented_bluepill 0.0.46 → 0.0.47
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +8 -0
- data/Gemfile +4 -0
- data/Rakefile +2 -54
- data/bin/bluepill +2 -3
- data/bin/sample_forking_server +55 -0
- data/evented_bluepill.gemspec +20 -79
- data/lib/bluepill.rb +7 -4
- data/lib/bluepill/application.rb +32 -75
- data/lib/bluepill/application/client.rb +3 -1
- data/lib/bluepill/application/server.rb +5 -3
- data/lib/bluepill/condition_watch.rb +25 -19
- data/lib/bluepill/controller.rb +14 -12
- data/lib/bluepill/dsl.rb +7 -151
- data/lib/bluepill/dsl/app_proxy.rb +29 -0
- data/lib/bluepill/dsl/process_factory.rb +87 -0
- data/lib/bluepill/dsl/process_proxy.rb +39 -0
- data/lib/bluepill/event.rb +25 -0
- data/lib/bluepill/group.rb +25 -18
- data/lib/bluepill/logger.rb +11 -9
- data/lib/bluepill/process.rb +139 -149
- data/lib/bluepill/process_conditions.rb +3 -1
- data/lib/bluepill/process_conditions/always_true.rb +4 -2
- data/lib/bluepill/process_conditions/cpu_usage.rb +4 -2
- data/lib/bluepill/process_conditions/http.rb +2 -0
- data/lib/bluepill/process_conditions/mem_usage.rb +6 -4
- data/lib/bluepill/process_conditions/process_condition.rb +6 -4
- data/lib/bluepill/process_statistics.rb +3 -1
- data/lib/bluepill/socket.rb +29 -9
- data/lib/bluepill/system.rb +50 -52
- data/lib/bluepill/trigger.rb +39 -37
- data/lib/bluepill/triggers/flapping.rb +16 -18
- data/lib/bluepill/util/rotational_array.rb +15 -13
- data/lib/bluepill/version.rb +3 -1
- data/lib/example.rb +2 -1
- data/lib/runit_example.rb +2 -0
- metadata +29 -23
- data/VERSION +0 -1
- data/bin/bpsv +0 -3
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Rakefile
CHANGED
@@ -1,54 +1,2 @@
|
|
1
|
-
require '
|
2
|
-
|
3
|
-
|
4
|
-
begin
|
5
|
-
require 'jeweler'
|
6
|
-
Jeweler::Tasks.new do |gem|
|
7
|
-
gem.name = "bluepill"
|
8
|
-
gem.summary = %Q{A process monitor written in Ruby with stability and minimalism in mind.}
|
9
|
-
gem.description = %Q{Bluepill keeps your daemons up while taking up as little resources as possible. After all you probably want the resources of your server to be used by whatever daemons you are running rather than the thing that's supposed to make sure they are brought back up, should they die or misbehave.}
|
10
|
-
gem.email = "entombedvirus@gmail.com"
|
11
|
-
gem.homepage = "http://github.com/arya/bluepill"
|
12
|
-
gem.authors = ["Arya Asemanfar", "Gary Tsang", "Rohith Ravi"]
|
13
|
-
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
14
|
-
gem.add_dependency("daemons", ">= 1.0.9")
|
15
|
-
gem.add_dependency("blankslate", ">= 2.1.2.2")
|
16
|
-
gem.add_dependency("state_machine", ">= 0.8.0")
|
17
|
-
gem.add_dependency("activesupport", ">= 2.3.4")
|
18
|
-
|
19
|
-
gem.files -= ["bin/sample_forking_server"]
|
20
|
-
gem.executables = ["bluepill"]
|
21
|
-
end
|
22
|
-
rescue LoadError
|
23
|
-
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
24
|
-
end
|
25
|
-
|
26
|
-
|
27
|
-
require 'rake/rdoctask'
|
28
|
-
Rake::RDocTask.new do |rdoc|
|
29
|
-
if File.exist?('VERSION')
|
30
|
-
version = File.read('VERSION')
|
31
|
-
else
|
32
|
-
version = ""
|
33
|
-
end
|
34
|
-
|
35
|
-
rdoc.rdoc_dir = 'rdoc'
|
36
|
-
rdoc.title = "blue-pill #{version}"
|
37
|
-
rdoc.rdoc_files.include('README*')
|
38
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
39
|
-
end
|
40
|
-
|
41
|
-
|
42
|
-
namespace :version do
|
43
|
-
desc "Update version of Bluepill in source code"
|
44
|
-
task :update_file do
|
45
|
-
version = File.read("VERSION").strip
|
46
|
-
File.open("lib/bluepill/version.rb", "w") do |file|
|
47
|
-
file.write <<-END
|
48
|
-
module Bluepill
|
49
|
-
VERSION = "#{version}"
|
50
|
-
end
|
51
|
-
END
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
1
|
+
require 'bundler'
|
2
|
+
Bundler::GemHelper.install_tasks
|
data/bin/bluepill
CHANGED
@@ -0,0 +1,55 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
# -*- encoding: utf-8 -*-
|
3
|
+
|
4
|
+
# This is a modified version found at http://tomayko.com/writings/unicorn-is-unix
|
5
|
+
# It is modified to trigger various states like increase memory consumption so that
|
6
|
+
# I could write watches for them.
|
7
|
+
|
8
|
+
# Instructions for running the test
|
9
|
+
#
|
10
|
+
# (1) Edit the example config and fix the path to this file. Around line 16.
|
11
|
+
# (2) Load up the config and run the bluepill daemon
|
12
|
+
# (3) Run watch -n0.2 'sudo ruby bin/bluepill status 2>/dev/null; echo; ps ajxu | egrep "(CPU|forking|bluepill|sleep|ruby)" | grep -v grep | sort'
|
13
|
+
# (4) After verifying that the "sleep" workers are properly being restarted, telnet to localhost 4242 and say something. You should get it echoed back and the worker which answered your request should now be over the allowed memory limit
|
14
|
+
# (5) Observe the worker being killed in the watch you started in step 3.
|
15
|
+
|
16
|
+
require 'socket'
|
17
|
+
|
18
|
+
port = ARGV[0].to_i
|
19
|
+
port = 4242 if port == 0
|
20
|
+
|
21
|
+
acceptor = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
|
22
|
+
address = Socket.pack_sockaddr_in(port, '127.0.0.1')
|
23
|
+
acceptor.bind(address)
|
24
|
+
acceptor.listen(10)
|
25
|
+
|
26
|
+
children = []
|
27
|
+
trap('EXIT') { acceptor.close; children.each {|c| Process.kill('QUIT', c)} }
|
28
|
+
|
29
|
+
File.open('/tmp/bp/pids/process_0.pid', 'w') { |x| x.write(::Process.pid) }
|
30
|
+
|
31
|
+
3.times do
|
32
|
+
children << fork do
|
33
|
+
trap('QUIT') {$0 = "forking_server| QUIT received shutting down gracefully..."; sleep 5; exit}
|
34
|
+
trap('INT') {$0 = "forking_server| INT received shutting down UN-gracefully..."; sleep 3; exit}
|
35
|
+
|
36
|
+
puts "child #$$ accepting on shared socket (localhost:#{port})"
|
37
|
+
loop {
|
38
|
+
socket, addr = acceptor.accept
|
39
|
+
socket.write "child #$$ echo> "
|
40
|
+
socket.flush
|
41
|
+
message = socket.gets
|
42
|
+
socket.write message
|
43
|
+
socket.close
|
44
|
+
puts "child #$$ echo'd: '#{message.strip}'"
|
45
|
+
|
46
|
+
# cause a spike in mem usage
|
47
|
+
temp = "*" * (100 * 1024)
|
48
|
+
}
|
49
|
+
exit
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
trap('INT') { puts "\nbailing" ; exit }
|
54
|
+
|
55
|
+
Process.waitall
|
data/evented_bluepill.gemspec
CHANGED
@@ -1,86 +1,27 @@
|
|
1
|
-
# Generated by jeweler
|
2
|
-
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
1
|
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "bluepill/version"
|
5
4
|
|
6
5
|
Gem::Specification.new do |s|
|
7
|
-
s.name
|
8
|
-
s.version
|
9
|
-
|
10
|
-
s.
|
11
|
-
s.
|
12
|
-
s.
|
13
|
-
s.
|
6
|
+
s.name = "evented_bluepill"
|
7
|
+
s.version = Bluepill::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Stefan Huber", "Arya Asemanfar", "Gary Tsang", "Rohith Ravi"]
|
10
|
+
s.email = ["MSNexploder@gmail.com"]
|
11
|
+
s.homepage = "http://github.com/msnexploder/evented_bluepill"
|
12
|
+
s.summary = %q{A process monitor written in Ruby with stability and minimalism in mind.}
|
14
13
|
s.description = %q{Bluepill keeps your daemons up while taking up as little resources as possible. After all you probably want the resources of your server to be used by whatever daemons you are running rather than the thing that's supposed to make sure they are brought back up, should they die or misbehave.}
|
15
|
-
s.email = %q{MSNexploder@gmail.com}
|
16
|
-
s.executables = ["bluepill"]
|
17
|
-
s.extra_rdoc_files = [
|
18
|
-
"LICENSE",
|
19
|
-
"README.md"
|
20
|
-
]
|
21
|
-
s.files = [
|
22
|
-
"DESIGN.md",
|
23
|
-
"LICENSE",
|
24
|
-
"README.md",
|
25
|
-
"Rakefile",
|
26
|
-
"VERSION",
|
27
|
-
"bin/bluepill",
|
28
|
-
"bin/bpsv",
|
29
|
-
"evented_bluepill.gemspec",
|
30
|
-
"lib/bluepill.rb",
|
31
|
-
"lib/bluepill/application.rb",
|
32
|
-
"lib/bluepill/application/client.rb",
|
33
|
-
"lib/bluepill/application/server.rb",
|
34
|
-
"lib/bluepill/condition_watch.rb",
|
35
|
-
"lib/bluepill/controller.rb",
|
36
|
-
"lib/bluepill/dsl.rb",
|
37
|
-
"lib/bluepill/group.rb",
|
38
|
-
"lib/bluepill/logger.rb",
|
39
|
-
"lib/bluepill/process.rb",
|
40
|
-
"lib/bluepill/process_conditions.rb",
|
41
|
-
"lib/bluepill/process_conditions/always_true.rb",
|
42
|
-
"lib/bluepill/process_conditions/cpu_usage.rb",
|
43
|
-
"lib/bluepill/process_conditions/http.rb",
|
44
|
-
"lib/bluepill/process_conditions/mem_usage.rb",
|
45
|
-
"lib/bluepill/process_conditions/process_condition.rb",
|
46
|
-
"lib/bluepill/process_statistics.rb",
|
47
|
-
"lib/bluepill/socket.rb",
|
48
|
-
"lib/bluepill/system.rb",
|
49
|
-
"lib/bluepill/trigger.rb",
|
50
|
-
"lib/bluepill/triggers/flapping.rb",
|
51
|
-
"lib/bluepill/util/rotational_array.rb",
|
52
|
-
"lib/bluepill/version.rb",
|
53
|
-
"lib/example.rb",
|
54
|
-
"lib/runit_example.rb"
|
55
|
-
]
|
56
|
-
s.homepage = %q{http://github.com/msnexploder/evented_bluepill}
|
57
|
-
s.require_paths = ["lib"]
|
58
|
-
s.rubygems_version = %q{1.3.7}
|
59
|
-
s.summary = %q{A process monitor written in Ruby with stability and minimalism in mind.}
|
60
14
|
|
61
|
-
|
62
|
-
|
63
|
-
|
15
|
+
s.add_dependency 'daemons', '~> 1.0.10'
|
16
|
+
s.add_dependency 'blankslate', '~> 2.1.2.3'
|
17
|
+
s.add_dependency 'state_machine', '~> 0.8.1'
|
18
|
+
s.add_dependency 'activesupport', '~> 2.3.10'
|
19
|
+
s.add_dependency 'cool.io', '~> 1.0.0'
|
64
20
|
|
65
|
-
|
66
|
-
s.add_runtime_dependency(%q<daemons>, [">= 1.0.9"])
|
67
|
-
s.add_runtime_dependency(%q<blankslate>, [">= 2.1.2.2"])
|
68
|
-
s.add_runtime_dependency(%q<state_machine>, [">= 0.8.0"])
|
69
|
-
s.add_runtime_dependency(%q<activesupport>, [">= 2.3.4"])
|
70
|
-
s.add_runtime_dependency(%q<cool.io>, [">= 1.0.0"])
|
71
|
-
else
|
72
|
-
s.add_dependency(%q<daemons>, [">= 1.0.9"])
|
73
|
-
s.add_dependency(%q<blankslate>, [">= 2.1.2.2"])
|
74
|
-
s.add_dependency(%q<state_machine>, [">= 0.8.0"])
|
75
|
-
s.add_dependency(%q<activesupport>, [">= 2.3.4"])
|
76
|
-
s.add_dependency(%q<cool.io>, [">= 1.0.0"])
|
77
|
-
end
|
78
|
-
else
|
79
|
-
s.add_dependency(%q<daemons>, [">= 1.0.9"])
|
80
|
-
s.add_dependency(%q<blankslate>, [">= 2.1.2.2"])
|
81
|
-
s.add_dependency(%q<state_machine>, [">= 0.8.0"])
|
82
|
-
s.add_dependency(%q<activesupport>, [">= 2.3.4"])
|
83
|
-
s.add_dependency(%q<cool.io>, [">= 1.0.0"])
|
84
|
-
end
|
85
|
-
end
|
21
|
+
s.rubyforge_project = "evented_bluepill"
|
86
22
|
|
23
|
+
s.files = `git ls-files`.split("\n")
|
24
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
25
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
26
|
+
s.require_paths = ["lib"]
|
27
|
+
end
|
data/lib/bluepill.rb
CHANGED
@@ -1,16 +1,16 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
1
3
|
require 'rubygems'
|
2
4
|
|
3
|
-
require 'thread'
|
4
5
|
require 'monitor'
|
5
6
|
require 'syslog'
|
6
7
|
require 'timeout'
|
7
8
|
require 'logger'
|
8
9
|
|
9
|
-
require 'active_support/inflector'
|
10
|
-
require 'active_support/core_ext/hash'
|
11
10
|
require 'active_support/core_ext/numeric'
|
12
|
-
require 'active_support/
|
11
|
+
require 'active_support/core_ext/hash'
|
13
12
|
|
13
|
+
require 'bluepill/event'
|
14
14
|
require 'bluepill/application'
|
15
15
|
require 'bluepill/controller'
|
16
16
|
require 'bluepill/socket'
|
@@ -21,6 +21,9 @@ require "bluepill/logger"
|
|
21
21
|
require "bluepill/condition_watch"
|
22
22
|
require 'bluepill/trigger'
|
23
23
|
require 'bluepill/triggers/flapping'
|
24
|
+
require 'bluepill/dsl/process_factory'
|
25
|
+
require 'bluepill/dsl/process_proxy'
|
26
|
+
require 'bluepill/dsl/app_proxy'
|
24
27
|
require "bluepill/dsl"
|
25
28
|
require "bluepill/system"
|
26
29
|
|
data/lib/bluepill/application.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
2
|
|
3
3
|
module Bluepill
|
4
4
|
class Application
|
5
5
|
PROCESS_COMMANDS = [:start, :stop, :restart, :unmonitor, :status]
|
6
|
-
|
7
|
-
attr_accessor :name, :logger, :
|
6
|
+
|
7
|
+
attr_accessor :name, :logger, :cmd_listener, :base_dir, :pid_file
|
8
8
|
attr_accessor :groups, :work_queue
|
9
9
|
attr_accessor :pids_dir, :log_file
|
10
10
|
|
@@ -12,29 +12,23 @@ module Bluepill
|
|
12
12
|
self.name = name
|
13
13
|
|
14
14
|
@foreground = options[:foreground]
|
15
|
-
self.log_file = options[:log_file]
|
15
|
+
self.log_file = options[:log_file]
|
16
16
|
self.base_dir = options[:base_dir] || '/var/bluepill'
|
17
17
|
self.pid_file = File.join(self.base_dir, 'pids', self.name + ".pid")
|
18
18
|
self.pids_dir = File.join(self.base_dir, 'pids', self.name)
|
19
19
|
|
20
20
|
self.groups = {}
|
21
|
-
|
21
|
+
|
22
22
|
self.logger = Bluepill::Logger.new(:log_file => self.log_file, :stdout => foreground?).prefix_with(self.name)
|
23
|
-
|
23
|
+
|
24
24
|
self.setup_signal_traps
|
25
25
|
self.setup_pids_dir
|
26
|
-
|
27
|
-
@mutex = Mutex.new
|
28
26
|
end
|
29
27
|
|
30
28
|
def foreground?
|
31
29
|
!!@foreground
|
32
30
|
end
|
33
31
|
|
34
|
-
def mutex(&b)
|
35
|
-
@mutex.synchronize(&b)
|
36
|
-
end
|
37
|
-
|
38
32
|
def load
|
39
33
|
begin
|
40
34
|
self.start_server
|
@@ -45,7 +39,7 @@ module Bluepill
|
|
45
39
|
exit(5)
|
46
40
|
end
|
47
41
|
end
|
48
|
-
|
42
|
+
|
49
43
|
PROCESS_COMMANDS.each do |command|
|
50
44
|
class_eval <<-END
|
51
45
|
def #{command}(group_name = nil, process_name = nil)
|
@@ -53,19 +47,20 @@ module Bluepill
|
|
53
47
|
end
|
54
48
|
END
|
55
49
|
end
|
56
|
-
|
50
|
+
|
57
51
|
def add_process(process, group_name = nil)
|
58
52
|
group_name = group_name.to_s if group_name
|
59
|
-
|
53
|
+
|
60
54
|
self.groups[group_name] ||= Group.new(group_name, :logger => self.logger.prefix_with(group_name))
|
61
55
|
self.groups[group_name].add_process(process)
|
62
56
|
end
|
63
|
-
|
57
|
+
|
64
58
|
def version
|
65
59
|
Bluepill::VERSION
|
66
60
|
end
|
67
61
|
|
68
62
|
protected
|
63
|
+
|
69
64
|
def send_to_process_or_group(method, group_name, process_name)
|
70
65
|
if group_name.nil? && process_name.nil?
|
71
66
|
self.groups.values.collect do |group|
|
@@ -84,90 +79,52 @@ module Bluepill
|
|
84
79
|
end
|
85
80
|
end
|
86
81
|
|
87
|
-
def start_listener
|
88
|
-
@listener_thread.kill if @listener_thread
|
89
|
-
@listener_thread = Thread.new do
|
90
|
-
loop do
|
91
|
-
begin
|
92
|
-
client = self.socket.accept
|
93
|
-
command, *args = client.readline.strip.split(":")
|
94
|
-
response = begin
|
95
|
-
mutex { self.send(command, *args) }
|
96
|
-
rescue Exception => e
|
97
|
-
e
|
98
|
-
end
|
99
|
-
client.write(Marshal.dump(response))
|
100
|
-
rescue StandardError => e
|
101
|
-
logger.err("Got exception in cmd listener: %s `%s`" % [e.class.name, e.message])
|
102
|
-
e.backtrace.each {|l| logger.err(l)}
|
103
|
-
ensure
|
104
|
-
begin
|
105
|
-
client.close
|
106
|
-
rescue IOError
|
107
|
-
# closed stream
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
82
|
def start_server
|
115
83
|
self.kill_previous_bluepill
|
116
|
-
|
84
|
+
|
117
85
|
Daemonize.daemonize unless foreground?
|
118
|
-
|
86
|
+
|
119
87
|
self.logger.reopen
|
120
|
-
|
88
|
+
|
121
89
|
$0 = "bluepilld: #{self.name}"
|
122
|
-
|
90
|
+
|
123
91
|
self.groups.each {|_, group| group.determine_initial_state }
|
124
92
|
|
125
|
-
|
126
93
|
self.write_pid_file
|
127
|
-
self.
|
128
|
-
self.
|
129
|
-
|
130
|
-
|
131
|
-
end
|
132
|
-
|
133
|
-
def run
|
134
|
-
@running = true # set to false by signal trap
|
135
|
-
while @running
|
136
|
-
mutex do
|
137
|
-
System.reset_data
|
138
|
-
self.groups.each { |_, group| group.tick }
|
139
|
-
end
|
140
|
-
sleep 1
|
141
|
-
end
|
94
|
+
self.cmd_listener = Bluepill::Socket.server(self.base_dir, self.name, self)
|
95
|
+
Bluepill::Event.attach(self.cmd_listener)
|
96
|
+
Bluepill::Event.run
|
97
|
+
|
142
98
|
cleanup
|
143
99
|
end
|
144
|
-
|
100
|
+
|
145
101
|
def cleanup
|
146
|
-
|
102
|
+
# TODO ugly
|
103
|
+
File.unlink(Bluepill::Socket.socket_path(self.base_dir, self.name)) if self.cmd_listener
|
147
104
|
File.unlink(self.pid_file) if File.exists?(self.pid_file)
|
148
105
|
end
|
149
|
-
|
106
|
+
|
150
107
|
def setup_signal_traps
|
151
|
-
terminator =
|
108
|
+
terminator = Proc.new do
|
152
109
|
puts "Terminating..."
|
153
|
-
|
110
|
+
Bluepill::Event.stop
|
154
111
|
end
|
155
|
-
|
156
|
-
Signal.trap("TERM", &terminator)
|
157
|
-
Signal.trap("INT", &terminator)
|
158
|
-
|
112
|
+
|
113
|
+
Signal.trap("TERM", &terminator)
|
114
|
+
Signal.trap("INT", &terminator)
|
115
|
+
|
159
116
|
Signal.trap("HUP") do
|
160
117
|
self.logger.reopen if self.logger
|
161
118
|
end
|
162
119
|
end
|
163
|
-
|
120
|
+
|
164
121
|
def setup_pids_dir
|
165
122
|
FileUtils.mkdir_p(self.pids_dir) unless File.exists?(self.pids_dir)
|
166
123
|
# we need everybody to be able to write to the pids_dir as processes managed by
|
167
124
|
# bluepill will be writing to this dir after they've dropped privileges
|
168
125
|
FileUtils.chmod(0777, self.pids_dir)
|
169
126
|
end
|
170
|
-
|
127
|
+
|
171
128
|
def kill_previous_bluepill
|
172
129
|
if File.exists?(self.pid_file)
|
173
130
|
previous_pid = File.read(self.pid_file).to_i
|
@@ -194,7 +151,7 @@ module Bluepill
|
|
194
151
|
end
|
195
152
|
end
|
196
153
|
end
|
197
|
-
|
154
|
+
|
198
155
|
def write_pid_file
|
199
156
|
File.open(self.pid_file, 'w') { |x| x.write(::Process.pid) }
|
200
157
|
end
|