bluepill 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
data/TODO CHANGED
@@ -1,6 +1,4 @@
1
- * Flap detection
2
1
  * Figure out proper logger lvl for each msg. So a person can choose only to log local6.warn and get only state transition messages and not any of the watch chatter.
3
- * Proper implementation of the cpu and mem watches. Possibly not forking to use ps ax?
4
2
  * Better error output than just vanilla exception traces
5
3
  * Better output for cli commands than just "ok"
6
4
  * munin support?
@@ -10,4 +8,5 @@ Issues encountered in the wild
10
8
  ------------------------------
11
9
 
12
10
  1. There were weird dependencies on xml-simple and builder gems when you try to use the bluepill cli.
13
- 2s. I think flap detection trigger has a bug in it. When couple bg workers quit right after bluepill attempted to start them, they went in to the unmonitored state but did not come back from it. Not sure if flap detection even got triggered cuz I did not see a flapping detected message in the log.
11
+ 2. Whenever bluepill executes user specified commands (like start_command, stop_command, restart_command), it should execute it in such a way that it does not affect the stability of bluepill daemon itself.
12
+ 3. Whenever a command is sent to a process group, execute them in parallel for each process in the group instead of serially.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.4
1
+ 0.0.5
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.4"
8
+ s.version = "0.0.5"
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-10-13}
12
+ s.date = %q{2009-10-14}
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}
@@ -47,6 +47,7 @@ Gem::Specification.new do |s|
47
47
  "lib/bluepill/process_conditions/mem_usage.rb",
48
48
  "lib/bluepill/process_conditions/process_condition.rb",
49
49
  "lib/bluepill/socket.rb",
50
+ "lib/bluepill/system.rb",
50
51
  "lib/bluepill/trigger.rb",
51
52
  "lib/bluepill/triggers/flapping.rb",
52
53
  "lib/bluepill/util/rotational_array.rb",
data/lib/bluepill.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'rubygems'
2
2
 
3
3
  require 'thread'
4
+ require 'monitor'
4
5
  require 'syslog'
5
6
 
6
7
  require 'active_support/inflector'
@@ -18,6 +19,7 @@ require "bluepill/condition_watch"
18
19
  require 'bluepill/trigger'
19
20
  require 'bluepill/triggers/flapping'
20
21
  require "bluepill/dsl"
22
+ require "bluepill/system"
21
23
 
22
24
  require "bluepill/process_conditions"
23
25
 
@@ -107,13 +107,13 @@ private
107
107
  Thread.new(self) do |app|
108
108
  begin
109
109
  loop do
110
- logger.info("Server | Command loop started:")
110
+ # logger.info("Server | Command loop started:")
111
111
  client = socket.accept
112
- logger.info("Server: Handling Request")
112
+ # logger.info("Server: Handling Request")
113
113
  cmd = client.readline.strip
114
- logger.info("Server: #{cmd}")
114
+ # logger.info("Server: #{cmd}")
115
115
  response = app.send(*cmd.split(":"))
116
- logger.info("Server: Sending Response")
116
+ # logger.info("Server: Sending Response")
117
117
  client.write(response)
118
118
  client.close
119
119
  end
@@ -126,11 +126,11 @@ private
126
126
  def worker
127
127
  Thread.new(self) do |app|
128
128
  loop do
129
- app.logger.info("Server | worker loop started:")
129
+ # app.logger.info("Server | worker loop started:")
130
130
  job = self.work_queue.pop
131
- app.logger.info("Server | worker job recieved:")
131
+ # app.logger.info("Server | worker job recieved:")
132
132
  send_to_process_or_group(job[0], job[1], false)
133
- app.logger.info("Server | worker job processed:")
133
+ # app.logger.info("Server | worker job processed:")
134
134
  end
135
135
  end
136
136
  end
@@ -165,6 +165,8 @@ private
165
165
 
166
166
  def run
167
167
  loop do
168
+ System.reset_data
169
+
168
170
  self.groups.each do |_, group|
169
171
  group.tick
170
172
  end
@@ -20,7 +20,7 @@ module Bluepill
20
20
  attr_accessor *CONFIGURABLE_ATTRIBUTES
21
21
 
22
22
  state_machine :initial => :unmonitored do
23
- state :unmonitored, :up, :down
23
+ state :unmonitored, :up, :down, :restarting
24
24
 
25
25
  event :tick do
26
26
  transition :unmonitored => :unmonitored
@@ -29,21 +29,24 @@ module Bluepill
29
29
  transition :up => :down, :unless => :process_running?
30
30
 
31
31
  transition :down => :up, :if => lambda {|process| process.process_running? || process.start_process }
32
+
33
+ transition :restarting => :up, :if => :process_running?
34
+ transition :restarting => :down, :unless => :process_running?
32
35
  end
33
36
 
34
37
  event :start do
35
38
  transition :unmonitored => :up, :if => lambda {|process| process.process_running? || process.start_process }
36
- transition :up => :up
39
+ transition [:restarting, :up] => :up
37
40
  transition :down => :up, :if => :start_process
38
41
  end
39
42
 
40
43
  event :stop do
41
44
  transition [:unmonitored, :down] => :unmonitored
42
- transition :up => :unmonitored, :if => :stop_process
45
+ transition [:up, :restarting] => :unmonitored, :if => :stop_process
43
46
  end
44
47
 
45
48
  event :restart do
46
- transition all => :up, :if => :restart_process
49
+ transition all => :restarting, :if => :restart_process
47
50
  end
48
51
 
49
52
  event :unmonitor do
@@ -63,7 +66,7 @@ module Bluepill
63
66
 
64
67
  def initialize(process_name, options = {})
65
68
  @name = process_name
66
- @event_mutex = Mutex.new
69
+ @event_mutex = Monitor.new
67
70
  @transition_history = Util::RotationalArray.new(10)
68
71
  @watches = []
69
72
  @triggers = []
@@ -205,6 +208,8 @@ module Bluepill
205
208
  stop_process
206
209
  start_process
207
210
  end
211
+
212
+ true
208
213
  end
209
214
 
210
215
  def daemonize?
@@ -6,7 +6,8 @@ module Bluepill
6
6
  end
7
7
 
8
8
  def run(pid)
9
- `ps ux -p #{pid} | tail -1 | awk '{print $3}'`.to_f
9
+ # third col in the ps axu output
10
+ System.ps_axu[pid][2].to_f
10
11
  end
11
12
 
12
13
  def check(value)
@@ -6,7 +6,8 @@ module Bluepill
6
6
  end
7
7
 
8
8
  def run(pid)
9
- `ps ux -p #{pid} | tail -1 | awk '{print $5}'`.to_f
9
+ # rss is on the 5th col
10
+ System.ps_axu[pid][4].to_f
10
11
  end
11
12
 
12
13
  def check(value)
@@ -0,0 +1,32 @@
1
+ require "singleton"
2
+ module Bluepill
3
+ # This class represents the system that bluepill is running on.. It's mainly used to memoize
4
+ # results of running ps auxx etc so that every watch in the every process will not result in a fork
5
+ module System
6
+ extend self
7
+
8
+ def store
9
+ @store ||= Hash.new
10
+ end
11
+
12
+ def reset_data
13
+ store.clear unless store.empty?
14
+ end
15
+
16
+ def ps_axu
17
+ store[:ps_axu] ||= begin
18
+ # BSD style ps invocation
19
+ lines = `ps axu`.split("\n")
20
+
21
+ lines.inject(Hash.new) do |mem, line|
22
+ # There are 11 cols in the ps ax output. This keeps programs that use spaces in $0 in one chunk
23
+ chunks = line.split(/\s+/, 11)
24
+ pid = chunks[1].to_i
25
+ mem[pid] = chunks
26
+
27
+ mem
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -26,10 +26,15 @@ module Bluepill
26
26
 
27
27
  def schedule_event(event, delay)
28
28
  # TODO: maybe wrap this in a ScheduledEvent class with methods like cancel
29
- Thread.new do
30
- sleep delay
31
- self.logger.info("Retrying from flapping")
32
- process.dispatch!(event)
29
+ Thread.new(self) do |trigger|
30
+ begin
31
+ sleep delay.to_i
32
+ trigger.logger.info("Retrying from flapping")
33
+ trigger.process.dispatch!(event)
34
+ rescue Exception => e
35
+ trigger.logger.error(e)
36
+ trigger.logger.error(e.backtrace.join("\n"))
37
+ end
33
38
  end
34
39
  end
35
40
 
@@ -1,7 +1,10 @@
1
1
  module Bluepill
2
2
  module Triggers
3
3
  class Flapping < Bluepill::Trigger
4
- UP_TO_DOWN = [:up, :down] # to avoid recreating this array on every notify
4
+ TRIGGER_STATES = [
5
+ [:up, :down],
6
+ [:up, :restarting]
7
+ ]
5
8
 
6
9
  PARAMS = [:times, :within, :retry_in]
7
10
 
@@ -20,7 +23,7 @@ module Bluepill
20
23
  end
21
24
 
22
25
  def notify(transition)
23
- if [transition.from_name, transition.to_name] == UP_TO_DOWN
26
+ if TRIGGER_STATES.include?([transition.from_name, transition.to_name])
24
27
  self.timeline << Time.now.to_i
25
28
  self.check_flapping
26
29
  end
data/lib/example.rb CHANGED
@@ -22,15 +22,15 @@ ROOT_DIR = "/tmp/bp"
22
22
  Bluepill.application(:sample_app) do |app|
23
23
  1.times do |i|
24
24
  app.process("process_#{i}") do |process|
25
- process.start_command = "sleep 2"
25
+ process.start_command = "while true; do echo ''; sleep 0.01; done"
26
26
  process.daemonize = true
27
27
  process.pid_file = "#{ROOT_DIR}/pids/process_#{i}.pid"
28
28
  process.uid = "admin"
29
29
  process.gid = "staff"
30
30
 
31
31
 
32
- # process.checks :cpu_usage, :every => 1, :below => 1, :times => [1,4]
33
- process.checks :flapping, :times => 2, :within => 30, :retry_in => 30
32
+ process.checks :cpu_usage, :every => 5, :below => 0.5, :times => [2, 5]
33
+ process.checks :flapping, :times => 2, :within => 30.seconds, :retry_in => 7.seconds
34
34
  end
35
35
  end
36
36
 
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.4
4
+ version: 0.0.5
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-10-13 00:00:00 -07:00
14
+ date: 2009-10-14 00:00:00 -07:00
15
15
  default_executable: bluepill
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
@@ -92,6 +92,7 @@ files:
92
92
  - lib/bluepill/process_conditions/mem_usage.rb
93
93
  - lib/bluepill/process_conditions/process_condition.rb
94
94
  - lib/bluepill/socket.rb
95
+ - lib/bluepill/system.rb
95
96
  - lib/bluepill/trigger.rb
96
97
  - lib/bluepill/triggers/flapping.rb
97
98
  - lib/bluepill/util/rotational_array.rb