bluepill 0.0.28 → 0.0.30

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.28
1
+ 0.0.30
data/bluepill.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{bluepill}
8
- s.version = "0.0.28"
8
+ s.version = "0.0.30"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Arya Asemanfar", "Gary Tsang", "Rohith Ravi"]
12
- s.date = %q{2009-12-26}
12
+ s.date = %q{2009-12-27}
13
13
  s.default_executable = %q{bluepill}
14
14
  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
15
  s.email = %q{entombedvirus@gmail.com}
@@ -43,6 +43,7 @@ Gem::Specification.new do |s|
43
43
  "lib/bluepill/process_conditions/cpu_usage.rb",
44
44
  "lib/bluepill/process_conditions/mem_usage.rb",
45
45
  "lib/bluepill/process_conditions/process_condition.rb",
46
+ "lib/bluepill/process_statistics.rb",
46
47
  "lib/bluepill/socket.rb",
47
48
  "lib/bluepill/system.rb",
48
49
  "lib/bluepill/trigger.rb",
data/lib/bluepill.rb CHANGED
@@ -16,6 +16,7 @@ require 'bluepill/application'
16
16
  require 'bluepill/controller'
17
17
  require 'bluepill/socket'
18
18
  require "bluepill/process"
19
+ require "bluepill/process_statistics"
19
20
  require "bluepill/group"
20
21
  require "bluepill/logger"
21
22
  require "bluepill/condition_watch"
@@ -1,6 +1,6 @@
1
1
  module Bluepill
2
2
  class Application
3
- PROCESS_COMMANDS = [:start, :stop, :restart, :unmonitor]
3
+ PROCESS_COMMANDS = [:start, :stop, :restart, :unmonitor, :status]
4
4
 
5
5
  attr_accessor :name, :logger, :base_dir, :socket, :pid_file
6
6
  attr_accessor :groups, :work_queue
@@ -33,49 +33,6 @@ module Bluepill
33
33
  end
34
34
  end
35
35
 
36
- def status
37
- buffer = []
38
- depth = 0
39
-
40
- if self.groups.has_key?(nil)
41
- self.groups[nil].processes.each do |p|
42
- buffer << "%s%s(pid:%s): %s" % [" " * depth, p.name, p.actual_pid.inspect, p.state]
43
-
44
- if p.monitor_children?
45
- depth += 2
46
- p.children.each do |c|
47
- buffer << "%s%s: %s" % [" " * depth, c.name, c.state]
48
- end
49
- depth -= 2
50
- end
51
- end
52
- end
53
-
54
- self.groups.each do |group_name, group|
55
- next if group_name.nil?
56
-
57
- buffer << "\n#{group_name}"
58
-
59
- group.processes.each do |p|
60
- depth += 2
61
-
62
- buffer << "%s%s(pid:%s): %s" % [" " * depth, p.name, p.actual_pid.inspect, p.state]
63
-
64
- if p.monitor_children?
65
- depth += 2
66
- p.children.each do |c|
67
- buffer << "%s%s: %s" % [" " * depth, c.name, c.state]
68
- end
69
- depth -= 2
70
- end
71
-
72
- depth -= 2
73
- end
74
- end
75
-
76
- buffer.join("\n")
77
- end
78
-
79
36
  PROCESS_COMMANDS.each do |command|
80
37
  class_eval <<-END
81
38
  def #{command}(group_name = nil, process_name = nil)
@@ -20,6 +20,8 @@ module Bluepill
20
20
 
21
21
  def handle_command(application, command, *args)
22
22
  case command.to_sym
23
+ when :status
24
+ puts self.send_to_daemon(application, :status, *args)
23
25
  when *Application::PROCESS_COMMANDS
24
26
  # these need to be sent to the daemon and the results printed out
25
27
  affected = self.send_to_daemon(application, command, *args)
@@ -31,8 +33,6 @@ module Bluepill
31
33
  puts " #{process}"
32
34
  end
33
35
  end
34
- when :status
35
- puts self.send_to_daemon(application, :status, *args)
36
36
  when :quit
37
37
  pid = pid_for(application)
38
38
  if System.pid_alive?(pid)
data/lib/bluepill/dsl.rb CHANGED
@@ -1,5 +1,10 @@
1
1
  require 'ostruct'
2
2
  module Bluepill
3
+ def self.define_process_condition(name, &block)
4
+ klass = Class.new(ProcessConditions::ProcessCondition, &block)
5
+ ProcessConditions.const_set("#{name.to_s.camelcase}", klass)
6
+ end
7
+
3
8
  def self.application(app_name, options = {}, &block)
4
9
  app = Application.new(app_name.to_s, options, &block)
5
10
 
@@ -36,5 +36,30 @@ module Bluepill
36
36
  end
37
37
  END
38
38
  end
39
+
40
+ def status(process_name = nil)
41
+ lines = []
42
+ if process_name.nil?
43
+ prefix = self.name ? " " : ""
44
+ lines << "#{self.name}:" if self.name
45
+
46
+ self.processes.each do |process|
47
+ lines << "%s%s(pid:%s): %s" % [prefix, process.name, process.actual_pid, process.state]
48
+ if process.monitor_children?
49
+ process.children.each do |child|
50
+ lines << " %s%s: %s" % [prefix, child.name, child.state]
51
+ end
52
+ end
53
+ end
54
+ else
55
+ self.processes.each do |process|
56
+ next if process_name != process.name
57
+ lines << "%s%s(pid:%s): %s" % [prefix, process.name, process.actual_pid, process.state]
58
+ lines << process.statistics.to_s
59
+ end
60
+ end
61
+ lines << ""
62
+ end
63
+
39
64
  end
40
65
  end
@@ -29,7 +29,7 @@ module Bluepill
29
29
 
30
30
  attr_accessor :name, :watches, :triggers, :logger, :skip_ticks_until
31
31
  attr_accessor *CONFIGURABLE_ATTRIBUTES
32
- attr_reader :children
32
+ attr_reader :children, :statistics
33
33
 
34
34
  state_machine :initial => :unmonitored do
35
35
  # These are the idle states, i.e. only an event (either external or internal) will trigger a transition.
@@ -91,6 +91,7 @@ module Bluepill
91
91
  @watches = []
92
92
  @triggers = []
93
93
  @children = []
94
+ @statistics = ProcessStatistics.new
94
95
 
95
96
  @monitor_children = options[:monitor_children] || false
96
97
 
@@ -133,8 +134,9 @@ module Bluepill
133
134
  end
134
135
 
135
136
  # State machine methods
136
- def dispatch!(event)
137
+ def dispatch!(event, reason = nil)
137
138
  @event_mutex.synchronize do
139
+ @statistics.record_event(event, reason)
138
140
  self.send("#{event}")
139
141
  end
140
142
  end
@@ -181,12 +183,14 @@ module Bluepill
181
183
  thread.join
182
184
  if thread[:events].size > 0
183
185
  logger.info "#{watch.name} dispatched: #{thread[:events].join(',')}"
184
- events << thread[:events]
186
+ thread[:events].each do |event|
187
+ events << [event, watch.to_s]
188
+ end
185
189
  end
186
190
  events
187
- end.flatten.uniq.each do |event|
191
+ end.each do |(event, reason)|
188
192
  break if @transitioned
189
- self.dispatch!(event)
193
+ self.dispatch!(event, reason)
190
194
  end
191
195
  end
192
196
 
@@ -206,11 +210,11 @@ module Bluepill
206
210
  logger.warning("Refusing to re-run start command on an automatically daemonized process to preserve currently running process pid file.")
207
211
  return
208
212
  end
209
- dispatch!(:start)
213
+ dispatch!(:start, "user initiated")
210
214
 
211
215
  when "stop"
212
216
  stop_process
213
- dispatch!(:unmonitor)
217
+ dispatch!(:unmonitor, "user initiated")
214
218
 
215
219
  when "restart"
216
220
  restart_process
@@ -219,7 +223,7 @@ module Bluepill
219
223
  # When the user issues an unmonitor cmd, reset any triggers so that
220
224
  # scheduled events gets cleared
221
225
  triggers.each {|t| t.reset! }
222
- dispatch!(:unmonitor)
226
+ dispatch!(:unmonitor, "user initiated")
223
227
  end
224
228
  end
225
229
 
@@ -1,6 +1,10 @@
1
1
  module Bluepill
2
2
  module ProcessConditions
3
3
  class ProcessCondition
4
+ def initialize(options = {})
5
+ @options = options
6
+ end
7
+
4
8
  def run(pid)
5
9
  raise "Implement in subclass!"
6
10
  end
@@ -0,0 +1,24 @@
1
+ module Bluepill
2
+ class ProcessStatistics
3
+ STRFTIME = "%m/%d/%Y %H:%I:%S"
4
+ # possibly persist this data.
5
+ def initialize
6
+ @events = Util::RotationalArray.new(10)
7
+ end
8
+
9
+ def record_event(event, reason)
10
+ @events.push([event, reason, Time.now])
11
+ end
12
+
13
+ def to_s
14
+ str = []
15
+ @events.each do |(event, reason, time)|
16
+ str << " #{event} at #{time.strftime(STRFTIME)} - #{reason || "unspecified"}"
17
+ end
18
+ if str.size > 0
19
+ str << "event history:"
20
+ end
21
+ str.reverse.join("\n")
22
+ end
23
+ end
24
+ end
@@ -27,7 +27,7 @@ module Bluepill
27
27
  end
28
28
 
29
29
  def dispatch!(event)
30
- self.process.dispatch!(event)
30
+ self.process.dispatch!(event, self.class.name.split("::").last)
31
31
  end
32
32
 
33
33
  def schedule_event(event, delay)
@@ -36,7 +36,7 @@ module Bluepill
36
36
  begin
37
37
  sleep delay.to_f
38
38
  trigger.logger.info("Retrying from flapping")
39
- trigger.process.dispatch!(event)
39
+ trigger.dispatch!(event)
40
40
  trigger.mutex.synchronize do
41
41
  trigger.scheduled_events.delete_if { |_, thread| thread == Thread.current }
42
42
  end
@@ -48,6 +48,14 @@ module Bluepill
48
48
  super
49
49
  end
50
50
 
51
+ def each(&block)
52
+ times = @counter >= @capacity ? @capacity : @counter
53
+ start = @counter >= @capacity ? rotational_idx(@counter) : 0
54
+ times.times do |i|
55
+ block.call(self[rotational_idx(start + i)])
56
+ end
57
+ end
58
+
51
59
  private
52
60
 
53
61
  def rotational_idx(idx)
@@ -1,3 +1,3 @@
1
1
  module Bluepill
2
- VERSION = "0.0.28"
2
+ VERSION = "0.0.30"
3
3
  end
data/lib/example.rb CHANGED
@@ -3,6 +3,16 @@ require 'bluepill'
3
3
  require 'logger'
4
4
 
5
5
  ROOT_DIR = "/tmp/bp"
6
+ Bluepill.define_process_condition(:random_watch) do
7
+ def run(pid)
8
+ (rand * 100).to_i / 100.0
9
+ end
10
+
11
+ def check(value)
12
+ value > @options[:fails_at]
13
+ false
14
+ end
15
+ end
6
16
 
7
17
  # Watch with
8
18
  # watch -n0.2 'ps axu | egrep "(CPU|forking|bluepill|sleep)" | grep -v grep | sort'
@@ -61,7 +71,7 @@ Bluepill.application(:sample_app) do |app|
61
71
  end
62
72
  end
63
73
 
64
- 1.times do |i|
74
+ 2.times do |i|
65
75
  app.process("group_process_#{i}") do |process|
66
76
  process.uid = "arya"
67
77
  process.gid = "wheel"
@@ -71,11 +81,14 @@ Bluepill.application(:sample_app) do |app|
71
81
 
72
82
 
73
83
  process.group = "grouped"
74
- process.start_command = %Q{cd /tmp && ruby -e '$stderr.puts("hello stderr");$stdout.puts("hello stdout"); $stdout.flush; $stderr.flush; sleep 10'}
84
+ # process.start_command = %Q{cd /tmp && ruby -e '$stderr.puts("hello stderr");$stdout.puts("hello stdout"); $stdout.flush; $stderr.flush; sleep 10'}
85
+ process.start_command = "sleep 20"
86
+ process.stop_command = "kill {{PID}}"
75
87
  process.daemonize = true
76
88
  process.pid_file = "/tmp/p_#{process.group}_#{i}.pid"
77
89
 
78
- # process.checks :always_true, :every => 5
90
+ process.checks :random_watch, :every => 2, :fails_at => 0.5
91
+ process.checks :flapping, :times => 2, :within => 900.seconds, :retry_in => 7.seconds
79
92
  end
80
93
  end
81
94
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bluepill
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.28
4
+ version: 0.0.30
5
5
  platform: ruby
6
6
  authors:
7
7
  - Arya Asemanfar
@@ -11,7 +11,7 @@ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
13
 
14
- date: 2009-12-26 00:00:00 -08:00
14
+ date: 2009-12-27 00:00:00 -08:00
15
15
  default_executable: bluepill
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
@@ -88,6 +88,7 @@ files:
88
88
  - lib/bluepill/process_conditions/cpu_usage.rb
89
89
  - lib/bluepill/process_conditions/mem_usage.rb
90
90
  - lib/bluepill/process_conditions/process_condition.rb
91
+ - lib/bluepill/process_statistics.rb
91
92
  - lib/bluepill/socket.rb
92
93
  - lib/bluepill/system.rb
93
94
  - lib/bluepill/trigger.rb