bluepill 0.0.68 → 0.0.69

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -2
  3. data/bin/bluepill +19 -20
  4. data/bin/sample_forking_server +26 -13
  5. data/bluepill.gemspec +12 -18
  6. data/lib/bluepill.rb +12 -12
  7. data/lib/bluepill/application.rb +64 -71
  8. data/lib/bluepill/application/client.rb +0 -2
  9. data/lib/bluepill/application/server.rb +1 -3
  10. data/lib/bluepill/condition_watch.rb +12 -7
  11. data/lib/bluepill/controller.rb +37 -42
  12. data/lib/bluepill/dsl.rb +1 -2
  13. data/lib/bluepill/dsl/app_proxy.rb +3 -4
  14. data/lib/bluepill/dsl/process_factory.rb +40 -44
  15. data/lib/bluepill/dsl/process_proxy.rb +4 -5
  16. data/lib/bluepill/group.rb +15 -21
  17. data/lib/bluepill/logger.rb +4 -4
  18. data/lib/bluepill/process.rb +107 -109
  19. data/lib/bluepill/process_conditions.rb +1 -3
  20. data/lib/bluepill/process_conditions/always_true.rb +2 -3
  21. data/lib/bluepill/process_conditions/cpu_usage.rb +0 -1
  22. data/lib/bluepill/process_conditions/file_time.rb +5 -6
  23. data/lib/bluepill/process_conditions/http.rb +11 -9
  24. data/lib/bluepill/process_conditions/mem_usage.rb +6 -7
  25. data/lib/bluepill/process_conditions/process_condition.rb +4 -5
  26. data/lib/bluepill/process_conditions/running_time.rb +1 -2
  27. data/lib/bluepill/process_conditions/zombie_process.rb +1 -2
  28. data/lib/bluepill/process_journal.rb +18 -21
  29. data/lib/bluepill/process_statistics.rb +2 -4
  30. data/lib/bluepill/socket.rb +13 -16
  31. data/lib/bluepill/system.rb +57 -63
  32. data/lib/bluepill/trigger.rb +9 -11
  33. data/lib/bluepill/triggers/flapping.rb +12 -16
  34. data/lib/bluepill/util/rotational_array.rb +1 -2
  35. data/lib/bluepill/version.rb +1 -2
  36. metadata +4 -28
  37. data/.gitignore +0 -12
  38. data/.rspec +0 -1
  39. data/.travis.yml +0 -17
  40. data/Gemfile +0 -27
  41. data/Rakefile +0 -38
  42. data/examples/example.rb +0 -87
  43. data/examples/new_example.rb +0 -89
  44. data/examples/new_runit_example.rb +0 -29
  45. data/examples/runit_example.rb +0 -26
  46. data/local-bluepill +0 -130
  47. data/spec/lib/bluepill/application_spec.rb +0 -51
  48. data/spec/lib/bluepill/logger_spec.rb +0 -3
  49. data/spec/lib/bluepill/process_spec.rb +0 -135
  50. data/spec/lib/bluepill/process_statistics_spec.rb +0 -24
  51. data/spec/lib/bluepill/system_spec.rb +0 -45
  52. data/spec/spec_helper.rb +0 -26
@@ -1,8 +1,6 @@
1
- # -*- encoding: utf-8 -*-
2
1
  module Bluepill
3
2
  module Application
4
3
  module Client
5
-
6
4
  end
7
5
  end
8
6
  end
@@ -1,10 +1,8 @@
1
- # -*- encoding: utf-8 -*-
2
1
  module Bluepill
3
2
  module Application
4
3
  module ServerMethods
5
-
6
4
  def status
7
- self.processes.collect do |process|
5
+ processes.collect do |process|
8
6
  "#{process.name} #{process.state}"
9
7
  end.join("\n")
10
8
  end
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  module Bluepill
3
2
  class HistoryValue < Struct.new(:value, :critical)
4
3
  end
@@ -11,9 +10,9 @@ module Bluepill
11
10
  @name = name
12
11
 
13
12
  @logger = options.delete(:logger)
14
- @fires = options.has_key?(:fires) ? Array(options.delete(:fires)) : [:restart]
13
+ @fires = options.key?(:fires) ? Array(options.delete(:fires)) : [:restart]
15
14
  @every = options.delete(:every)
16
- @times = options.delete(:times) || [1,1]
15
+ @times = options.delete(:times) || [1, 1]
17
16
  @times = [@times, @times] unless @times.is_a?(Array) # handles :times => 5
18
17
  @include_children = options.delete(:include_children) || false
19
18
 
@@ -26,9 +25,15 @@ module Bluepill
26
25
  if @last_ran_at.nil? || (@last_ran_at + @every) <= tick_number
27
26
  @last_ran_at = tick_number
28
27
 
29
- value = @process_condition.run(pid, @include_children)
28
+ begin
29
+ value = @process_condition.run(pid, @include_children)
30
+ rescue => e
31
+ logger.err(e.backtrace)
32
+ raise e
33
+ end
34
+
30
35
  @history << HistoryValue.new(@process_condition.format_value(value), @process_condition.check(value))
31
- self.logger.info(self.to_s)
36
+ logger.info(to_s)
32
37
 
33
38
  return @fires if self.fired?
34
39
  end
@@ -40,11 +45,11 @@ module Bluepill
40
45
  end
41
46
 
42
47
  def fired?
43
- @history.count {|v| not v.critical} >= @times.first
48
+ @history.count { |v| !v.critical } >= @times.first
44
49
  end
45
50
 
46
51
  def to_s
47
- data = @history.collect {|v| "#{v.value}#{'*' unless v.critical}"}.join(", ")
52
+ data = @history.collect { |v| "#{v.value}#{'*' unless v.critical}" }.join(', ')
48
53
  "#{@name}: [#{data}]\n"
49
54
  end
50
55
  end
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  require 'fileutils'
3
2
  require 'bluepill/system'
4
3
 
@@ -17,18 +16,18 @@ module Bluepill
17
16
  end
18
17
 
19
18
  def running_applications
20
- Dir[File.join(sockets_dir, "*.sock")].map{|x| File.basename(x, ".sock")}
19
+ Dir[File.join(sockets_dir, '*.sock')].map { |x| File.basename(x, '.sock') }
21
20
  end
22
21
 
23
22
  def handle_command(application, command, *args)
24
23
  case command.to_sym
25
24
  when :status
26
- puts self.send_to_daemon(application, :status, *args)
25
+ puts send_to_daemon(application, :status, *args)
27
26
  when *Application::PROCESS_COMMANDS
28
27
  # these need to be sent to the daemon and the results printed out
29
- affected = self.send_to_daemon(application, command, *args)
28
+ affected = send_to_daemon(application, command, *args)
30
29
  if affected.empty?
31
- puts "No processes effected"
30
+ puts 'No processes effected'
32
31
  else
33
32
  puts "Sent #{command} to:"
34
33
  affected.each do |process|
@@ -38,14 +37,14 @@ module Bluepill
38
37
  when :quit
39
38
  pid = pid_for(application)
40
39
  if System.pid_alive?(pid)
41
- ::Process.kill("TERM", pid)
40
+ ::Process.kill('TERM', pid)
42
41
  puts "Killing bluepilld[#{pid}]"
43
42
  else
44
43
  puts "bluepilld[#{pid}] not running"
45
44
  end
46
45
  when :log
47
- log_file_location = self.send_to_daemon(application, :log_file)
48
- log_file_location = self.log_file if log_file_location.to_s.strip.empty?
46
+ log_file_location = send_to_daemon(application, :log_file)
47
+ log_file_location = log_file if log_file_location.to_s.strip.empty?
49
48
 
50
49
  requested_pattern = args.first
51
50
  grep_pattern = self.grep_pattern(application, requested_pattern)
@@ -54,69 +53,65 @@ module Bluepill
54
53
  puts "Tailing log for #{requested_pattern}..."
55
54
  Kernel.exec(tail)
56
55
  else
57
- $stderr.puts "Unknown command `%s` (or application `%s` has not been loaded yet)" % [command, command]
56
+ $stderr.puts(format('Unknown command `%s` (or application `%s` has not been loaded yet)', command, command))
58
57
  exit(1)
59
58
  end
60
59
  end
61
60
 
62
61
  def send_to_daemon(application, command, *args)
63
- begin
64
- verify_version!(application)
65
-
66
- command = ([command, *args]).join(":")
67
- response = Socket.client_command(base_dir, application, command)
68
- if response.is_a?(Exception)
69
- $stderr.puts "Received error from server:"
70
- $stderr.puts response.inspect
71
- $stderr.puts response.backtrace.join("\n")
72
- exit(8)
73
- else
74
- response
75
- end
62
+ verify_version!(application)
76
63
 
77
- rescue Errno::ECONNREFUSED
78
- abort("Connection Refused: Server is not running")
64
+ command = ([command, *args]).join(':')
65
+ response = Socket.client_command(base_dir, application, command)
66
+ if response.is_a?(Exception)
67
+ $stderr.puts 'Received error from server:'
68
+ $stderr.puts response.inspect
69
+ $stderr.puts response.backtrace.join("\n")
70
+ exit(8)
71
+ else
72
+ response
79
73
  end
74
+
75
+ rescue Errno::ECONNREFUSED
76
+ abort('Connection Refused: Server is not running')
80
77
  end
81
78
 
82
79
  def grep_pattern(application, query = nil)
83
80
  pattern = [application, query].compact.join(':')
84
81
  ['\[.*', Regexp.escape(pattern), '.*'].compact.join
85
82
  end
86
- private
83
+
84
+ private
87
85
 
88
86
  def cleanup_bluepill_directory
89
- self.running_applications.each do |app|
87
+ running_applications.each do |app|
90
88
  pid = pid_for(app)
91
- if !pid || !System.pid_alive?(pid)
92
- pid_file = File.join(self.pids_dir, "#{app}.pid")
93
- sock_file = File.join(self.sockets_dir, "#{app}.sock")
94
- System.delete_if_exists(pid_file)
95
- System.delete_if_exists(sock_file)
96
- end
89
+ next if pid || System.pid_alive?(pid)
90
+ pid_file = File.join(pids_dir, "#{app}.pid")
91
+ sock_file = File.join(sockets_dir, "#{app}.sock")
92
+ System.delete_if_exists(pid_file)
93
+ System.delete_if_exists(sock_file)
97
94
  end
98
95
  end
99
96
 
100
97
  def pid_for(app)
101
- pid_file = File.join(self.pids_dir, "#{app}.pid")
102
- File.exists?(pid_file) && File.read(pid_file).to_i
98
+ pid_file = File.join(pids_dir, "#{app}.pid")
99
+ File.exist?(pid_file) && File.read(pid_file).to_i
103
100
  end
104
101
 
105
102
  def setup_dir_structure
106
103
  [@sockets_dir, @pids_dir].each do |dir|
107
- FileUtils.mkdir_p(dir) unless File.exists?(dir)
104
+ FileUtils.mkdir_p(dir) unless File.exist?(dir)
108
105
  end
109
106
  end
110
107
 
111
108
  def verify_version!(application)
112
- begin
113
- version = Socket.client_command(base_dir, application, "version")
114
- if version != Bluepill::VERSION
115
- abort("The running version of your daemon seems to be out of date.\nDaemon Version: #{version}, CLI Version: #{Bluepill::VERSION}")
116
- end
117
- rescue ArgumentError
118
- abort("The running version of your daemon seems to be out of date.")
109
+ version = Socket.client_command(base_dir, application, 'version')
110
+ if version != Bluepill::VERSION
111
+ abort("The running version of your daemon seems to be out of date.\nDaemon Version: #{version}, CLI Version: #{Bluepill::VERSION}")
119
112
  end
113
+ rescue ArgumentError
114
+ abort('The running version of your daemon seems to be out of date.')
120
115
  end
121
116
  end
122
117
  end
@@ -1,9 +1,8 @@
1
- # -*- encoding: utf-8 -*-
2
1
  module Bluepill
3
2
  def self.application(app_name, options = {}, &block)
4
3
  app_proxy = AppProxy.new(app_name, options)
5
4
  if block.arity == 0
6
- app_proxy.instance_eval &block
5
+ app_proxy.instance_eval(&block)
7
6
  else
8
7
  app_proxy.instance_exec(app_proxy, &block)
9
8
  end
@@ -1,9 +1,8 @@
1
- # -*- encoding: utf-8 -*-
2
1
  module Bluepill
3
2
  class AppProxy
4
- APP_ATTRIBUTES = [:working_dir, :uid, :gid, :environment, :auto_start ]
3
+ APP_ATTRIBUTES = [:working_dir, :uid, :gid, :environment, :auto_start]
5
4
 
6
- attr_accessor *APP_ATTRIBUTES
5
+ attr_accessor(*APP_ATTRIBUTES)
7
6
  attr_reader :app
8
7
 
9
8
  def initialize(app_name, options)
@@ -12,7 +11,7 @@ module Bluepill
12
11
 
13
12
  def process(process_name, &process_block)
14
13
  attributes = {}
15
- APP_ATTRIBUTES.each { |a| attributes[a] = self.send(a) }
14
+ APP_ATTRIBUTES.each { |a| attributes[a] = send(a) }
16
15
 
17
16
  process_factory = ProcessFactory.new(attributes, process_block)
18
17
 
@@ -1,10 +1,9 @@
1
- # -*- encoding: utf-8 -*-
2
1
  module Bluepill
3
2
  class ProcessFactory
4
3
  attr_reader :attributes
5
4
 
6
- @@process_keys = Hash.new
7
- @@pid_files = Hash.new
5
+ @@process_keys = {}
6
+ @@pid_files = {}
8
7
 
9
8
  def initialize(attributes, process_block)
10
9
  @attributes = attributes
@@ -12,7 +11,7 @@ module Bluepill
12
11
  end
13
12
 
14
13
  def create_process(name, pids_dir)
15
- self.assign_default_pid_file(name, pids_dir)
14
+ assign_default_pid_file(name, pids_dir)
16
15
 
17
16
  process = ProcessProxy.new(name, @attributes, @process_block)
18
17
  child_process_block = @attributes.delete(:child_process_block)
@@ -24,7 +23,7 @@ module Bluepill
24
23
 
25
24
  def create_child_process(name, pid, logger)
26
25
  attributes = {}
27
- [:start_grace_time, :stop_grace_time, :restart_grace_time].each {|a| attributes[a] = @attributes[a]}
26
+ [:start_grace_time, :stop_grace_time, :restart_grace_time].each { |a| attributes[a] = @attributes[a] }
28
27
  attributes[:actual_pid] = pid
29
28
  attributes[:logger] = logger
30
29
 
@@ -36,19 +35,18 @@ module Bluepill
36
35
  process
37
36
  end
38
37
 
39
- protected
38
+ protected
40
39
 
41
40
  def assign_default_pid_file(process_name, pids_dir)
42
- unless @attributes.key?(:pid_file)
43
- group_name = @attributes[:group]
44
- default_pid_name = [group_name, process_name].compact.join('_').gsub(/[^A-Za-z0-9_\-]/, "_")
45
- @attributes[:pid_file] = File.join(pids_dir, default_pid_name + ".pid")
46
- end
41
+ return if @attributes.key?(:pid_file)
42
+ group_name = @attributes[:group]
43
+ default_pid_name = [group_name, process_name].compact.join('_').gsub(/[^A-Za-z0-9_\-]/, '_')
44
+ @attributes[:pid_file] = File.join(pids_dir, default_pid_name + '.pid')
47
45
  end
48
46
 
49
47
  def validate_process!(process)
50
48
  # validate uniqueness of group:process
51
- process_key = [process.attributes[:group], process.name].join(":")
49
+ process_key = [process.attributes[:group], process.name].join(':')
52
50
  if @@process_keys.key?(process_key)
53
51
  $stderr.print "Config Error: You have two entries for the process name '#{process.name}'"
54
52
  $stderr.print " in the group '#{process.attributes[:group]}'" if process.attributes.key?(:group)
@@ -60,7 +58,7 @@ module Bluepill
60
58
 
61
59
  # validate required attributes
62
60
  [:start_command].each do |required_attr|
63
- if !process.attributes.key?(required_attr)
61
+ unless process.attributes.key?(required_attr)
64
62
  $stderr.puts "Config Error: You must specify a #{required_attr} for '#{process.name}'"
65
63
  exit(6)
66
64
  end
@@ -75,48 +73,46 @@ module Bluepill
75
73
  @@pid_files[pid_key] = 0
76
74
  end
77
75
 
78
- #validate stop_signals array
76
+ # validate stop_signals array
79
77
  stop_grace_time = process.attributes[:stop_grace_time]
80
78
  stop_signals = process.attributes[:stop_signals]
81
79
 
82
- unless stop_signals.nil?
83
- #Start with the more helpful error messages before the 'odd number' message.
84
- delay_sum = 0
85
- stop_signals.each_with_index do |s_or_d, i|
86
- if i % 2 == 0
87
- signal = s_or_d
88
- unless signal.is_a? Symbol
89
- $stderr.puts "Config Error: Invalid stop_signals! Expected a symbol (signal) at position #{i} instead of '#{signal}'."
90
- exit(6)
91
- end
92
- else
93
- delay = s_or_d
94
- unless delay.is_a? Fixnum
95
- $stderr.puts "Config Error: Invalid stop_signals! Expected a number (delay) at position #{i} instead of '#{delay}'."
96
- exit(6)
97
- end
98
- delay_sum += delay
80
+ return if stop_signals.nil?
81
+ # Start with the more helpful error messages before the 'odd number' message.
82
+ delay_sum = 0
83
+ stop_signals.each_with_index do |s_or_d, i|
84
+ if i.even?
85
+ signal = s_or_d
86
+ unless signal.is_a? Symbol
87
+ $stderr.puts "Config Error: Invalid stop_signals! Expected a symbol (signal) at position #{i} instead of '#{signal}'."
88
+ exit(6)
89
+ end
90
+ else
91
+ delay = s_or_d
92
+ unless delay.is_a? Fixnum
93
+ $stderr.puts "Config Error: Invalid stop_signals! Expected a number (delay) at position #{i} instead of '#{delay}'."
94
+ exit(6)
99
95
  end
96
+ delay_sum += delay
100
97
  end
98
+ end
101
99
 
102
- unless stop_signals.size % 2 == 1
103
- $stderr.puts "Config Error: Invalid stop_signals! Expected an odd number of elements."
104
- exit(6)
105
- end
100
+ unless stop_signals.size.odd?
101
+ $stderr.puts 'Config Error: Invalid stop_signals! Expected an odd number of elements.'
102
+ exit(6)
103
+ end
106
104
 
107
- if stop_grace_time.nil? || stop_grace_time <= delay_sum
108
- $stderr.puts "Config Error: Stop_grace_time should be greater than the sum of stop_signals delays!"
109
- exit(6)
110
- end
105
+ if stop_grace_time.nil? || stop_grace_time <= delay_sum
106
+ $stderr.puts 'Config Error: Stop_grace_time should be greater than the sum of stop_signals delays!'
107
+ exit(6)
111
108
  end
112
109
  end
113
110
 
114
111
  def validate_child_process!(child)
115
- unless child.attributes.has_key?(:stop_command)
116
- $stderr.puts "Config Error: Invalid child process monitor for #{child.name}"
117
- $stderr.puts "You must specify a stop command to monitor child processes."
118
- exit(6)
119
- end
112
+ return if child.attributes.key?(:stop_command)
113
+ $stderr.puts "Config Error: Invalid child process monitor for #{child.name}"
114
+ $stderr.puts 'You must specify a stop command to monitor child processes.'
115
+ exit(6)
120
116
  end
121
117
  end
122
118
  end
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  module Bluepill
3
2
  class ProcessProxy
4
3
  attr_reader :attributes, :watches, :name
@@ -7,8 +6,8 @@ module Bluepill
7
6
  @attributes = attributes
8
7
  @watches = {}
9
8
 
10
- if process_block.arity == 0
11
- instance_eval &process_block
9
+ if process_block.arity.zero?
10
+ instance_eval(&process_block)
12
11
  else
13
12
  instance_exec(self, &process_block)
14
13
  end
@@ -16,11 +15,11 @@ module Bluepill
16
15
 
17
16
  def method_missing(name, *args)
18
17
  if args.size == 1 && name.to_s =~ /^(.*)=$/
19
- @attributes[$1.to_sym] = args.first
18
+ @attributes[Regexp.last_match[1].to_sym] = args.first
20
19
  elsif args.size == 1
21
20
  @attributes[name.to_sym] = args.first
22
21
  elsif args.size == 0 && name.to_s =~ /^(.*)!$/
23
- @attributes[$1.to_sym] = true
22
+ @attributes[Regexp.last_match[1].to_sym] = true
24
23
  elsif args.empty? && @attributes.key?(name.to_sym)
25
24
  @attributes[name.to_sym]
26
25
  else
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  module Bluepill
3
2
  class Group
4
3
  attr_accessor :name, :processes, :logger
@@ -11,20 +10,16 @@ module Bluepill
11
10
  end
12
11
 
13
12
  def add_process(process)
14
- process.logger = self.logger.prefix_with(process.name)
15
- self.processes << process
13
+ process.logger = logger.prefix_with(process.name)
14
+ processes << process
16
15
  end
17
16
 
18
17
  def tick
19
- self.processes.each do |process|
20
- process.tick
21
- end
18
+ processes.each(&:tick)
22
19
  end
23
20
 
24
21
  def determine_initial_state
25
- self.processes.each do |process|
26
- process.determine_initial_state
27
- end
22
+ processes.each(&:determine_initial_state)
28
23
  end
29
24
 
30
25
  # proxied events
@@ -55,26 +50,25 @@ module Bluepill
55
50
  def status(process_name = nil)
56
51
  lines = []
57
52
  if process_name.nil?
58
- prefix = self.name ? " " : ""
59
- lines << "#{self.name}:" if self.name
53
+ prefix = name ? ' ' : ''
54
+ lines << "#{name}:" if name
60
55
 
61
- self.processes.each do |process|
62
- lines << "%s%s(pid:%s): %s" % [prefix, process.name, process.actual_pid, process.state]
63
- if process.monitor_children?
64
- process.children.each do |child|
65
- lines << " %s%s: %s" % [prefix, child.name, child.state]
66
- end
56
+ processes.each do |process|
57
+ next unless process.monitor_children?
58
+ lines << format('%s%s(pid:%s): %s', prefix, process.name, process.actual_pid, process.state)
59
+ process.children.each do |child|
60
+ lines << format(' %s%s: %s', prefix, child.name, child.state)
67
61
  end
68
62
  end
63
+
69
64
  else
70
- self.processes.each do |process|
65
+ processes.each do |process|
71
66
  next if process_name != process.name
72
- lines << "%s%s(pid:%s): %s" % [prefix, process.name, process.actual_pid, process.state]
67
+ lines << format('%s%s(pid:%s): %s', prefix, process.name, process.actual_pid, process.state)
73
68
  lines << process.statistics.to_s
74
69
  end
75
70
  end
76
- lines << ""
71
+ lines << ''
77
72
  end
78
-
79
73
  end
80
74
  end