bluepill 0.0.68 → 0.0.69

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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