class Bluepill::Application
Constants
- PROCESS_COMMANDS
Attributes
base_dir[RW]
groups[RW]
kill_timeout[RW]
log_file[RW]
logger[RW]
name[RW]
pid_file[RW]
pids_dir[RW]
socket[RW]
work_queue[RW]
Public Class Methods
new(name, options = {})
click to toggle source
# File lib/bluepill/application.rb, line 13 def initialize(name, options = {}) self.name = name @foreground = options[:foreground] self.log_file = options[:log_file] self.base_dir = ProcessJournal.base_dir = options[:base_dir] || ENV['BLUEPILL_BASE_DIR'] || (::Process.euid != 0 ? File.join(ENV['HOME'], '.bluepill') : '/var/run/bluepill') self.pid_file = File.join(base_dir, 'pids', self.name + '.pid') self.pids_dir = File.join(base_dir, 'pids', self.name) self.kill_timeout = options[:kill_timeout] || 10 self.groups = {} self.logger = ProcessJournal.logger = Bluepill::Logger.new(log_file: log_file, stdout: foreground?).prefix_with(self.name) setup_signal_traps setup_pids_dir @mutex = Mutex.new end
Public Instance Methods
add_process(process, group_name = nil)
click to toggle source
# File lib/bluepill/application.rb, line 60 def add_process(process, group_name = nil) group_name = group_name.to_s if group_name groups[group_name] ||= Group.new(group_name, logger: logger.prefix_with(group_name)) groups[group_name].add_process(process) end
foreground?()
click to toggle source
# File lib/bluepill/application.rb, line 35 def foreground? !!@foreground end
load()
click to toggle source
# File lib/bluepill/application.rb, line 43 def load start_server rescue StandardError => e $stderr.puts('Failed to start bluepill:') $stderr.puts(format('%s `%s`', e.class.name, e.message)) $stderr.puts(e.backtrace) exit(5) end
mutex(&b)
click to toggle source
# File lib/bluepill/application.rb, line 39 def mutex(&b) @mutex.synchronize(&b) end
version()
click to toggle source
# File lib/bluepill/application.rb, line 67 def version Bluepill::Version end
Protected Instance Methods
cleanup()
click to toggle source
# File lib/bluepill/application.rb, line 155 def cleanup ProcessJournal.kill_all_from_all_journals ProcessJournal.clear_all_atomic_fs_locks begin System.delete_if_exists(socket.path) if socket rescue IOError end System.delete_if_exists(pid_file) end
kill_previous_bluepill()
click to toggle source
# File lib/bluepill/application.rb, line 187 def kill_previous_bluepill return unless File.exist?(pid_file) previous_pid = File.read(pid_file).to_i return unless System.pid_alive?(previous_pid) ::Process.kill(0, previous_pid) puts "Killing previous bluepilld[#{previous_pid}]" ::Process.kill(2, previous_pid) rescue => e $stderr.puts 'Encountered error trying to kill previous bluepill:' $stderr.puts "#{e.class}: #{e.message}" exit(4) unless e.is_a?(Errno::ESRCH) else kill_timeout.times do |_i| sleep 0.5 break unless System.pid_alive?(previous_pid) end if System.pid_alive?(previous_pid) $stderr.puts "Previous bluepilld[#{previous_pid}] didn't die" exit(4) end end
run()
click to toggle source
# File lib/bluepill/application.rb, line 144 def run @running = true # set to false by signal trap while @running mutex do System.reset_data groups.each { |_, group| group.tick } end sleep 1 end end
send_to_process_or_group(method, group_name, process_name)
click to toggle source
# File lib/bluepill/application.rb, line 73 def send_to_process_or_group(method, group_name, process_name) if group_name.nil? && process_name.nil? groups.values.collect do |group| group.send(method) end.flatten elsif groups.key?(group_name) groups[group_name].send(method, process_name) elsif process_name.nil? # they must be targeting just by process name process_name = group_name groups.values.collect do |group| group.send(method, process_name) end.flatten else [] end end
setup_pids_dir()
click to toggle source
# File lib/bluepill/application.rb, line 180 def setup_pids_dir FileUtils.mkdir_p(pids_dir) unless File.exist?(pids_dir) # we need everybody to be able to write to the pids_dir as processes managed by # bluepill will be writing to this dir after they've dropped privileges FileUtils.chmod(0777, pids_dir) end
setup_signal_traps()
click to toggle source
# File lib/bluepill/application.rb, line 165 def setup_signal_traps terminator = proc do puts 'Terminating...' cleanup @running = false end Signal.trap('TERM', &terminator) Signal.trap('INT', &terminator) Signal.trap('HUP') do logger.reopen if logger end end
start_listener()
click to toggle source
# File lib/bluepill/application.rb, line 91 def start_listener @listener_thread.kill if @listener_thread @listener_thread = Thread.new do loop do begin client = socket.accept client.close_on_exec = true if client.respond_to?(:close_on_exec=) command, *args = client.readline.strip.split(':') response = begin mutex { send(command, *args) } rescue => e e end client.write(Marshal.dump(response)) rescue StandardError => e logger.err(format('Got exception in cmd listener: %s `%s`', e.class.name, e.message)) e.backtrace.each { |l| logger.err(l) } ensure begin client.close rescue IOError # closed stream end end end end end
start_server()
click to toggle source
# File lib/bluepill/application.rb, line 119 def start_server kill_previous_bluepill ProcessJournal.kill_all_from_all_journals ProcessJournal.clear_all_atomic_fs_locks begin ::Process.setpgid(0, 0) rescue Errno::EPERM end Daemonize.daemonize unless foreground? logger.reopen $0 = "bluepilld: #{name}" groups.each { |_, group| group.determine_initial_state } write_pid_file self.socket = Bluepill::Socket.server(base_dir, name) start_listener run end
write_pid_file()
click to toggle source
# File lib/bluepill/application.rb, line 210 def write_pid_file File.open(pid_file, 'w') { |x| x.write(::Process.pid) } end