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 CHANGED
@@ -2,4 +2,7 @@
2
2
  .DS_Store
3
3
  coverage
4
4
  rdoc
5
- pkg
5
+ pkg/*
6
+ *.gem
7
+ .bundle
8
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source :rubygems
2
+
3
+ # Specify your gem's dependencies in bluepill.gemspec
4
+ gemspec
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
  Bluepill is a simple process monitoring tool written in Ruby.
3
3
 
4
4
  ## Installation
5
- It's hosted on [gemcutter.org][gemcutter].
5
+ It's hosted on [rubygems.org][rubygems].
6
6
 
7
7
  sudo gem install bluepill
8
8
 
@@ -224,5 +224,5 @@ Bugs/Features: [http://github.com/arya/bluepill/issues](http://github.com/arya/b
224
224
  Mailing List: [http://groups.google.com/group/bluepill-rb](http://groups.google.com/group/bluepill-rb)
225
225
 
226
226
 
227
- [gemcutter]: http://gemcutter.org
227
+ [rubygems]: http://rubygems.org/gems/bluepill
228
228
 
data/Rakefile CHANGED
@@ -1,57 +1,4 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'rubygems'
4
- require 'rake'
5
-
6
- begin
7
- require 'jeweler'
8
- Jeweler::Tasks.new do |gem|
9
- gem.name = "bluepill"
10
- gem.summary = %Q{A process monitor written in Ruby with stability and minimalism in mind.}
11
- 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.}
12
- gem.email = "entombedvirus@gmail.com"
13
- gem.homepage = "http://github.com/arya/bluepill"
14
- gem.authors = ["Arya Asemanfar", "Gary Tsang", "Rohith Ravi"]
15
- # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
16
- gem.add_dependency("i18n", ">= 0.5.0")
17
- gem.add_dependency("daemons", ">= 1.0.9")
18
- gem.add_dependency("blankslate", ">= 2.1.2.2")
19
- gem.add_dependency("state_machine", ">= 0.8.0", "<=0.9.4")
20
- gem.add_dependency("activesupport", ">= 2.3.4")
21
-
22
- gem.files -= ["bin/sample_forking_server"]
23
- gem.executables = ["bluepill"]
24
- end
25
- rescue LoadError
26
- puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
27
- end
28
-
29
-
30
- require 'rake/rdoctask'
31
- Rake::RDocTask.new do |rdoc|
32
- if File.exist?('VERSION')
33
- version = File.read('VERSION')
34
- else
35
- version = ""
36
- end
37
-
38
- rdoc.rdoc_dir = 'rdoc'
39
- rdoc.title = "blue-pill #{version}"
40
- rdoc.rdoc_files.include('README*')
41
- rdoc.rdoc_files.include('lib/**/*.rb')
42
- end
43
-
44
-
45
- namespace :version do
46
- desc "Update version of Bluepill in source code"
47
- task :update_file do
48
- version = File.read("VERSION").strip
49
- File.open("lib/bluepill/version.rb", "w") do |file|
50
- file.write <<-END
51
- module Bluepill
52
- VERSION = "#{version}"
53
- end
54
- END
55
- end
56
- end
57
- end
3
+ require 'bundler'
4
+ Bundler::GemHelper.install_tasks
data/bin/bluepill CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env ruby
1
+ #! /usr/bin/env ruby
2
2
  require 'optparse'
3
3
  require 'bluepill'
4
4
 
@@ -0,0 +1,53 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ # This is a modified version found at http://tomayko.com/writings/unicorn-is-unix
4
+ # It is modified to trigger various states like increase memory consumption so that
5
+ # I could write watches for them.
6
+
7
+ # Instructions for running the test
8
+ #
9
+ # (1) Edit the example config and fix the path to this file. Around line 16.
10
+ # (2) Load up the config and run the bluepill daemon
11
+ # (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'
12
+ # (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
13
+ # (5) Observe the worker being killed in the watch you started in step 3.
14
+
15
+ require 'socket'
16
+
17
+ port = ARGV[0].to_i
18
+ port = 4242 if port == 0
19
+
20
+ acceptor = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
21
+ address = Socket.pack_sockaddr_in(port, '127.0.0.1')
22
+ acceptor.bind(address)
23
+ acceptor.listen(10)
24
+
25
+ children = []
26
+ trap('EXIT') { acceptor.close; children.each {|c| Process.kill('QUIT', c)} }
27
+
28
+
29
+ 3.times do
30
+ children << fork do
31
+ trap('QUIT') {$0 = "forking_server| QUIT received shutting down gracefully..."; sleep 5; exit}
32
+ trap('INT') {$0 = "forking_server| INT received shutting down UN-gracefully..."; sleep 3; exit}
33
+
34
+ puts "child #$$ accepting on shared socket (localhost:#{port})"
35
+ loop {
36
+ socket, addr = acceptor.accept
37
+ socket.write "child #$$ echo> "
38
+ socket.flush
39
+ message = socket.gets
40
+ socket.write message
41
+ socket.close
42
+ puts "child #$$ echo'd: '#{message.strip}'"
43
+
44
+ # cause a spike in mem usage
45
+ temp = "*" * (100 * 1024)
46
+ }
47
+ exit
48
+ end
49
+ end
50
+
51
+ trap('INT') { puts "\nbailing" ; exit }
52
+
53
+ Process.waitall
data/bluepill.gemspec CHANGED
@@ -1,88 +1,28 @@
1
- # Generated by jeweler
2
- # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
1
  # -*- encoding: utf-8 -*-
5
2
 
6
- Gem::Specification.new do |s|
7
- s.name = %q{bluepill}
8
- s.version = "0.0.46"
3
+ $LOAD_PATH.push File.expand_path("../lib", __FILE__)
4
+
5
+ require "bluepill/version"
9
6
 
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Arya Asemanfar", "Gary Tsang", "Rohith Ravi"]
12
- s.date = %q{2011-03-25}
13
- s.default_executable = %q{bluepill}
7
+ Gem::Specification.new do |s|
8
+ s.name = "bluepill"
9
+ s.version = Bluepill::VERSION
10
+ s.platform = Gem::Platform::RUBY
11
+ s.authors = ["Arya Asemanfar", "Gary Tsang", "Rohith Ravi"]
12
+ s.email = ["entombedvirus@gmail.com"]
13
+ s.homepage = "http://github.com/arya/bluepill"
14
+ s.summary = %q{A process monitor written in Ruby with stability and minimalism in mind.}
14
15
  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{entombedvirus@gmail.com}
16
- s.executables = ["bluepill"]
17
- s.extra_rdoc_files = [
18
- "LICENSE",
19
- "README.md"
20
- ]
21
- s.files = [
22
- ".gitignore",
23
- "DESIGN.md",
24
- "LICENSE",
25
- "README.md",
26
- "Rakefile",
27
- "VERSION",
28
- "bin/bluepill",
29
- "bin/bpsv",
30
- "bluepill.gemspec",
31
- "lib/bluepill.rb",
32
- "lib/bluepill/application.rb",
33
- "lib/bluepill/application/client.rb",
34
- "lib/bluepill/application/server.rb",
35
- "lib/bluepill/condition_watch.rb",
36
- "lib/bluepill/controller.rb",
37
- "lib/bluepill/dsl.rb",
38
- "lib/bluepill/group.rb",
39
- "lib/bluepill/logger.rb",
40
- "lib/bluepill/process.rb",
41
- "lib/bluepill/process_conditions.rb",
42
- "lib/bluepill/process_conditions/always_true.rb",
43
- "lib/bluepill/process_conditions/cpu_usage.rb",
44
- "lib/bluepill/process_conditions/http.rb",
45
- "lib/bluepill/process_conditions/mem_usage.rb",
46
- "lib/bluepill/process_conditions/process_condition.rb",
47
- "lib/bluepill/process_statistics.rb",
48
- "lib/bluepill/socket.rb",
49
- "lib/bluepill/system.rb",
50
- "lib/bluepill/trigger.rb",
51
- "lib/bluepill/triggers/flapping.rb",
52
- "lib/bluepill/util/rotational_array.rb",
53
- "lib/bluepill/version.rb",
54
- "lib/example.rb",
55
- "lib/runit_example.rb"
56
- ]
57
- s.homepage = %q{http://github.com/arya/bluepill}
58
- s.rdoc_options = ["--charset=UTF-8"]
59
- s.require_paths = ["lib"]
60
- s.rubygems_version = %q{1.3.7}
61
- s.summary = %q{A process monitor written in Ruby with stability and minimalism in mind.}
62
16
 
63
- if s.respond_to? :specification_version then
64
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
65
- s.specification_version = 3
17
+ s.add_dependency 'daemons', '~> 1.1.0'
18
+ s.add_dependency 'blankslate', '~> 2.1.2.3'
19
+ s.add_dependency 'state_machine', ['~> 0.8.0', '<=0.9.4']
20
+ s.add_dependency 'activesupport', '~> 2.3.4'
21
+ s.add_dependency 'i18n', '~> 0.5.0'
66
22
 
67
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
68
- s.add_runtime_dependency(%q<i18n>, [">= 0.5.0"])
69
- s.add_runtime_dependency(%q<daemons>, [">= 1.0.9"])
70
- s.add_runtime_dependency(%q<blankslate>, [">= 2.1.2.2"])
71
- s.add_runtime_dependency(%q<state_machine>, [">= 0.8.0", "<= 0.9.4"])
72
- s.add_runtime_dependency(%q<activesupport>, [">= 2.3.4"])
73
- else
74
- s.add_dependency(%q<i18n>, [">= 0.5.0"])
75
- s.add_dependency(%q<daemons>, [">= 1.0.9"])
76
- s.add_dependency(%q<blankslate>, [">= 2.1.2.2"])
77
- s.add_dependency(%q<state_machine>, [">= 0.8.0", "<= 0.9.4"])
78
- s.add_dependency(%q<activesupport>, [">= 2.3.4"])
79
- end
80
- else
81
- s.add_dependency(%q<i18n>, [">= 0.5.0"])
82
- s.add_dependency(%q<daemons>, [">= 1.0.9"])
83
- s.add_dependency(%q<blankslate>, [">= 2.1.2.2"])
84
- s.add_dependency(%q<state_machine>, [">= 0.8.0", "<= 0.9.4"])
85
- s.add_dependency(%q<activesupport>, [">= 2.3.4"])
86
- end
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
+ s.extra_rdoc_files = ["LICENSE", "README.md"]
87
28
  end
88
-
@@ -4,78 +4,78 @@ require 'logger'
4
4
 
5
5
  ROOT_DIR = "/tmp/bp"
6
6
 
7
- # Watch with
7
+ # Watch with
8
8
  # watch -n0.2 'ps axu | egrep "(CPU|forking|bluepill|sleep)" | grep -v grep | sort'
9
9
  Bluepill.application(:sample_app) do |app|
10
10
  0.times do |i|
11
11
  app.process("process_#{i}") do |process|
12
12
  process.pid_file = "#{ROOT_DIR}/pids/process_#{i}.pid"
13
-
13
+
14
14
  # I could not figure out a portable way to
15
15
  # specify the path to the sample forking server across the diff developer laptops.
16
16
  # Since this code is eval'ed we cannot reliably use __FILE__
17
17
  process.start_command = "/Users/rohith/work/bluepill/bin/sample_forking_server #{4242 + i}"
18
18
  process.stop_command = "kill -INT {{PID}}"
19
19
  process.daemonize = true
20
-
20
+
21
21
  process.start_grace_time = 1.seconds
22
22
  process.restart_grace_time = 7.seconds
23
23
  process.stop_grace_time = 7.seconds
24
-
24
+
25
25
  process.uid = "rohith"
26
26
  process.gid = "staff"
27
-
27
+
28
28
  # process.checks :cpu_usage, :every => 10, :below => 0.5, :times => [5, 5]
29
29
  process.checks :flapping, :times => 2, :within => 30.seconds, :retry_in => 7.seconds
30
-
30
+
31
31
  process.monitor_children do |child_process|
32
- # child_process.checks :cpu_usage,
33
- # :every => 10,
34
- # :below => 0.5,
32
+ # child_process.checks :cpu_usage,
33
+ # :every => 10,
34
+ # :below => 0.5,
35
35
  # :times => [5, 5]
36
-
37
- # child_process.checks :mem_usage,
38
- # :every => 3,
39
- # :below => 600.kilobytes,
40
- # :times => [3, 5],
36
+
37
+ # child_process.checks :mem_usage,
38
+ # :every => 3,
39
+ # :below => 600.kilobytes,
40
+ # :times => [3, 5],
41
41
  # :fires => [:stop]
42
-
42
+
43
43
  child_process.stop_command = "kill -QUIT {{PID}}"
44
44
  # child_process.checks :flapping, :times => 2, :within => 30.seconds, :retry_in => 7.seconds
45
45
  end
46
46
  end
47
47
  end
48
-
48
+
49
49
  0.times do |i|
50
50
  app.process("group_process_#{i}") do |process|
51
51
  process.group = "group_1"
52
52
  process.pid_file = "/Users/rohith/ffs/tmp/pids/mongrel_#{i}.pid"
53
53
  process.start_command = "cd ~/ffs && mongrel_rails start -P #{process.pid_file} -p 3000 -d"
54
-
54
+
55
55
  process.start_grace_time = 10.seconds
56
-
56
+
57
57
  process.uid = "rohith"
58
58
  process.gid = "staff"
59
-
59
+
60
60
  # process.checks :always_true, :every => 10
61
61
  end
62
62
  end
63
-
63
+
64
64
  1.times do |i|
65
65
  app.process("group_process_#{i}") do |process|
66
66
  process.uid = "rohith"
67
67
  process.gid = "wheel"
68
68
 
69
- process.stderr = "/tmp/err.log"
69
+ process.stderr = "/tmp/err.log"
70
70
  process.stdout = "/tmp/err.log"
71
71
 
72
-
72
+
73
73
  process.group = "grouped"
74
74
  process.start_command = %Q{cd /tmp && ruby -e '$stderr.puts("hello stderr");$stdout.puts("hello stdout"); $stdout.flush; $stderr.flush; sleep 10'}
75
75
  process.daemonize = true
76
76
  process.pid_file = "/tmp/noperm/p_#{process.group}_#{i}.pid"
77
-
77
+
78
78
  # process.checks :always_true, :every => 5
79
79
  end
80
80
  end
81
- end
81
+ end
@@ -1,3 +1,4 @@
1
+ #! /usr/bin/env ruby
1
2
  require 'rubygems'
2
3
  require 'bluepill'
3
4
  require 'logger'
@@ -5,16 +6,16 @@ require 'logger'
5
6
  # ATTENTION:
6
7
  # You must declare only one application per config when foreground mode specified
7
8
  #
8
- # http://github.com/akzhan/runit-man used as example of monitored application.
9
+ # http://github.com/Undev/runit-man used as example of monitored application.
9
10
 
10
11
  Bluepill.application(:runit_man, :foreground => true) do |app|
11
12
  app.process("runit-man") do |process|
12
13
  process.pid_file = "/etc/service/runit-man/supervise/pid"
13
-
14
+
14
15
  process.start_command = "/usr/bin/sv start runit-man"
15
16
  process.stop_command = "/usr/bin/sv stop runit-man"
16
17
  process.restart_command = "/usr/bin/sv restart runit-man"
17
-
18
+
18
19
  process.start_grace_time = 1.seconds
19
20
  process.restart_grace_time = 7.seconds
20
21
  process.stop_grace_time = 7.seconds
data/lib/bluepill.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # -*- encoding: utf-8 -*-
1
2
  require 'rubygems'
2
3
 
3
4
  require 'thread'
@@ -11,6 +12,10 @@ require 'active_support/core_ext/hash'
11
12
  require 'active_support/core_ext/numeric'
12
13
  require 'active_support/duration'
13
14
 
15
+ require 'bluepill/dsl/process_proxy'
16
+ require 'bluepill/dsl/process_factory'
17
+ require 'bluepill/dsl/app_proxy'
18
+
14
19
  require 'bluepill/application'
15
20
  require 'bluepill/controller'
16
21
  require 'bluepill/socket'
@@ -28,4 +33,4 @@ require "bluepill/process_conditions"
28
33
 
29
34
  require "bluepill/util/rotational_array"
30
35
 
31
- require "bluepill/version"
36
+ require "bluepill/version"
@@ -1,9 +1,10 @@
1
+ # -*- encoding: utf-8 -*-
1
2
  require 'thread'
2
3
 
3
4
  module Bluepill
4
5
  class Application
5
6
  PROCESS_COMMANDS = [:start, :stop, :restart, :unmonitor, :status]
6
-
7
+
7
8
  attr_accessor :name, :logger, :base_dir, :socket, :pid_file
8
9
  attr_accessor :groups, :work_queue
9
10
  attr_accessor :pids_dir, :log_file
@@ -12,18 +13,18 @@ module Bluepill
12
13
  self.name = name
13
14
 
14
15
  @foreground = options[:foreground]
15
- self.log_file = options[:log_file]
16
+ self.log_file = options[:log_file]
16
17
  self.base_dir = options[:base_dir] || '/var/bluepill'
17
18
  self.pid_file = File.join(self.base_dir, 'pids', self.name + ".pid")
18
19
  self.pids_dir = File.join(self.base_dir, 'pids', self.name)
19
20
 
20
21
  self.groups = {}
21
-
22
+
22
23
  self.logger = Bluepill::Logger.new(:log_file => self.log_file, :stdout => foreground?).prefix_with(self.name)
23
-
24
+
24
25
  self.setup_signal_traps
25
26
  self.setup_pids_dir
26
-
27
+
27
28
  @mutex = Mutex.new
28
29
  end
29
30
 
@@ -45,7 +46,7 @@ module Bluepill
45
46
  exit(5)
46
47
  end
47
48
  end
48
-
49
+
49
50
  PROCESS_COMMANDS.each do |command|
50
51
  class_eval <<-END
51
52
  def #{command}(group_name = nil, process_name = nil)
@@ -53,14 +54,14 @@ module Bluepill
53
54
  end
54
55
  END
55
56
  end
56
-
57
+
57
58
  def add_process(process, group_name = nil)
58
59
  group_name = group_name.to_s if group_name
59
-
60
+
60
61
  self.groups[group_name] ||= Group.new(group_name, :logger => self.logger.prefix_with(group_name))
61
62
  self.groups[group_name].add_process(process)
62
63
  end
63
-
64
+
64
65
  def version
65
66
  Bluepill::VERSION
66
67
  end
@@ -110,26 +111,26 @@ module Bluepill
110
111
  end
111
112
  end
112
113
  end
113
-
114
+
114
115
  def start_server
115
116
  self.kill_previous_bluepill
116
-
117
+
117
118
  Daemonize.daemonize unless foreground?
118
-
119
+
119
120
  self.logger.reopen
120
-
121
+
121
122
  $0 = "bluepilld: #{self.name}"
122
-
123
+
123
124
  self.groups.each {|_, group| group.determine_initial_state }
124
125
 
125
-
126
+
126
127
  self.write_pid_file
127
128
  self.socket = Bluepill::Socket.server(self.base_dir, self.name)
128
129
  self.start_listener
129
-
130
+
130
131
  self.run
131
132
  end
132
-
133
+
133
134
  def run
134
135
  @running = true # set to false by signal trap
135
136
  while @running
@@ -141,33 +142,33 @@ module Bluepill
141
142
  end
142
143
  cleanup
143
144
  end
144
-
145
+
145
146
  def cleanup
146
147
  File.unlink(self.socket.path) if self.socket
147
148
  File.unlink(self.pid_file) if File.exists?(self.pid_file)
148
149
  end
149
-
150
+
150
151
  def setup_signal_traps
151
152
  terminator = Proc.new do
152
153
  puts "Terminating..."
153
154
  @running = false
154
155
  end
155
-
156
- Signal.trap("TERM", &terminator)
157
- Signal.trap("INT", &terminator)
158
-
156
+
157
+ Signal.trap("TERM", &terminator)
158
+ Signal.trap("INT", &terminator)
159
+
159
160
  Signal.trap("HUP") do
160
161
  self.logger.reopen if self.logger
161
162
  end
162
163
  end
163
-
164
+
164
165
  def setup_pids_dir
165
166
  FileUtils.mkdir_p(self.pids_dir) unless File.exists?(self.pids_dir)
166
167
  # we need everybody to be able to write to the pids_dir as processes managed by
167
168
  # bluepill will be writing to this dir after they've dropped privileges
168
169
  FileUtils.chmod(0777, self.pids_dir)
169
170
  end
170
-
171
+
171
172
  def kill_previous_bluepill
172
173
  if File.exists?(self.pid_file)
173
174
  previous_pid = File.read(self.pid_file).to_i
@@ -194,7 +195,7 @@ module Bluepill
194
195
  end
195
196
  end
196
197
  end
197
-
198
+
198
199
  def write_pid_file
199
200
  File.open(self.pid_file, 'w') { |x| x.write(::Process.pid) }
200
201
  end