class Rack::App::Worker::Daemonizer
Constants
- DEFAULT_KILL_SIGNAL
Public Class Methods
new(daemon_name)
click to toggle source
# File lib/rack/app/worker/daemonizer.rb, line 6 def initialize(daemon_name) @daemon_name = daemon_name.to_s @on_shutdown, @on_halt, @on_reload = proc {}, proc {}, proc {} end
Public Instance Methods
bind(to_pid)
click to toggle source
# File lib/rack/app/worker/daemonizer.rb, line 63 def bind(to_pid) Thread.new do sleep(1) while Rack::App::Worker::Utils.process_alive?(to_pid) at_shutdown end end
daemonize()
click to toggle source
# File lib/rack/app/worker/daemonizer.rb, line 30 def daemonize case try_fork when NilClass #child subscribe_to_signals save_current_process_pid redirect else #parent Kernel.exit end end
has_running_process?()
click to toggle source
# File lib/rack/app/worker/daemonizer.rb, line 44 def has_running_process? pids.any? { |pid| Rack::App::Worker::Utils.process_alive?(pid) } end
id()
click to toggle source
# File lib/rack/app/worker/daemonizer.rb, line 11 def id @id ||= SecureRandom.uuid end
on_halt(&block)
click to toggle source
# File lib/rack/app/worker/daemonizer.rb, line 76 def on_halt(&block) raise('block not given!') unless block.is_a?(Proc) @on_halt = block end
on_reload(&block)
click to toggle source
# File lib/rack/app/worker/daemonizer.rb, line 81 def on_reload(&block) raise('block not given!') unless block.is_a?(Proc) @on_reload = block end
on_shutdown(&block)
click to toggle source
# File lib/rack/app/worker/daemonizer.rb, line 71 def on_shutdown(&block) raise('block not given!') unless block.is_a?(Proc) @on_shutdown = block end
process_title(new_title)
click to toggle source
# File lib/rack/app/worker/daemonizer.rb, line 48 def process_title(new_title) if Process.respond_to?(:setproctitle) Process.setproctitle(new_title) else $0 = new_title end end
send_signal(signal, to_amount_of_worker=pids.length)
click to toggle source
# File lib/rack/app/worker/daemonizer.rb, line 57 def send_signal(signal, to_amount_of_worker=pids.length) pids.take(to_amount_of_worker).each do |pid| kill(signal, pid) end end
spawn(&block)
click to toggle source
# File lib/rack/app/worker/daemonizer.rb, line 15 def spawn(&block) parent_pid = current_pid spawn_block = proc do subscribe_to_signals bind(parent_pid) save_current_process_pid redirect block.call(self) end try_fork(&spawn_block) end
subscribe_to_signals()
click to toggle source
# File lib/rack/app/worker/daemonizer.rb, line 86 def subscribe_to_signals ::Signal.trap('INT'){ at_shutdown } ::Signal.trap('HUP'){ at_shutdown } ::Signal.trap('TERM'){ at_halt } ::Signal.trap('USR1'){ at_reload } end
Protected Instance Methods
at_halt()
click to toggle source
# File lib/rack/app/worker/daemonizer.rb, line 117 def at_halt Timeout.timeout(10) { @on_halt.call } rescue nil ensure at_stop end
at_reload()
click to toggle source
# File lib/rack/app/worker/daemonizer.rb, line 123 def at_reload @on_reload.call end
at_shutdown()
click to toggle source
# File lib/rack/app/worker/daemonizer.rb, line 111 def at_shutdown @on_shutdown.call ensure at_stop end
at_stop()
click to toggle source
# File lib/rack/app/worker/daemonizer.rb, line 127 def at_stop File.write('/Users/aluzsi/Works/rack-app/worker/sandbox/out', pid_file_path) File.delete(pid_file_path) if File.exist?(pid_file_path) ::Kernel.exit end
current_pid()
click to toggle source
# File lib/rack/app/worker/daemonizer.rb, line 180 def current_pid Process.pid rescue $$ end
kill(signal, pid)
click to toggle source
Try and read the existing pid from the pid file and signal the process. Returns true for a non blocking status.
# File lib/rack/app/worker/daemonizer.rb, line 97 def kill(signal, pid) ::Process.kill(signal, pid) true rescue Errno::ESRCH $stdout.puts "The process #{pid} did not exist: Errno::ESRCH" true rescue Errno::EPERM $stderr.puts "Lack of privileges to manage the process #{pid}: Errno::EPERM" false rescue ::Exception => e $stderr.puts "While signaling the PID, unexpected #{e.class}: #{e}" false end
pid_file_path()
click to toggle source
# File lib/rack/app/worker/daemonizer.rb, line 170 def pid_file_path File.join(pids_folder_path, id) end
pids()
click to toggle source
# File lib/rack/app/worker/daemonizer.rb, line 165 def pids sorted_pid_files = Dir.glob(File.join(pids_folder_path, '*')).sort_by { |fp| File.mtime(fp) } sorted_pid_files.map { |file_path| File.read(file_path).to_i } end
pids_folder_path()
click to toggle source
# File lib/rack/app/worker/daemonizer.rb, line 174 def pids_folder_path path = Rack::App::Utils.pwd('pids', 'workers', @daemon_name) FileUtils.mkdir_p(path) path end
redirect()
click to toggle source
# File lib/rack/app/worker/daemonizer.rb, line 149 def redirect Timeout.timeout(5) { try_redirect } rescue Timeout::Error raise('Cannot redirect standard io channels!') end
save_current_process_pid()
click to toggle source
Attempts to write the pid of the forked process to the pid file.
# File lib/rack/app/worker/daemonizer.rb, line 142 def save_current_process_pid File.write(pid_file_path, current_pid) rescue ::Exception => e $stderr.puts "While writing the PID to file, unexpected #{e.class}: #{e}" Kernel.exit end
try_fork(&block)
click to toggle source
# File lib/rack/app/worker/daemonizer.rb, line 133 def try_fork(&block) pid = nil Timeout.timeout(15) { (Kernel.sleep(1) while (pid = ::Kernel.fork(&block)) == -1) } return pid rescue Timeout::Error raise('Fork failed!') end
try_redirect()
click to toggle source
Send stdout and stderr to log files for the child process
# File lib/rack/app/worker/daemonizer.rb, line 156 def try_redirect $stdin.reopen(Rack::App::Utils.devnull_path) $stdout.reopen(Rack::App::Worker::Environment.stdout) $stderr.reopen(Rack::App::Worker::Environment.stderr) $stdout.sync = $stderr.sync = true rescue Errno::ENOENT retry end