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.
@@ -0,0 +1,8 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg/*
6
+ *.gem
7
+ .bundle
8
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in lorem.gemspec
4
+ gemspec
data/Rakefile CHANGED
@@ -1,54 +1,2 @@
1
- require 'rubygems'
2
- require 'rake'
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
@@ -1,6 +1,5 @@
1
- #!/usr/bin/env ruby
2
- $LOAD_PATH << 'lib/'
3
-
1
+ #! /usr/bin/env ruby
2
+ # -*- encoding: utf-8 -*-
4
3
  require 'optparse'
5
4
  require 'bluepill'
6
5
 
@@ -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
@@ -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 = %q{evented_bluepill}
8
- s.version = "0.0.46"
9
-
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Stefan Huber", "Arya Asemanfar", "Gary Tsang", "Rohith Ravi"]
12
- s.date = %q{2011-01-10}
13
- s.default_executable = %q{bluepill}
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
- if s.respond_to? :specification_version then
62
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
63
- s.specification_version = 3
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
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
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
@@ -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/duration'
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
 
@@ -1,10 +1,10 @@
1
- require 'thread'
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, :base_dir, :socket, :pid_file
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.socket = Bluepill::Socket.server(self.base_dir, self.name)
128
- self.start_listener
129
-
130
- self.run
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
- File.unlink(self.socket.path) if self.socket
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 = lambda do
108
+ terminator = Proc.new do
152
109
  puts "Terminating..."
153
- @running = false
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