lib/daemon/daemon.rb in rsence-2.0.0.6.pre vs lib/daemon/daemon.rb in rsence-2.0.0.7.pre
- old
+ new
@@ -8,361 +8,350 @@
##
#++
# Use rubygems to load rack
require 'rubygems'
-require 'rack'
-# Loads the selected web-server (default is 'thin')
-require RSence.config[:http_server][:rack_require]
-
-# Methods that return rack the selected handler
-def rack_webrick_handler; Rack::Handler::WEBrick; end
-def rack_ebb_handler; Rack::Handler::Ebb; end
-def rack_thin_handler; Rack::Handler::Thin; end
-def rack_mongrel_handler; Rack::Handler::Mongrel; end
-def rack_unicorn_handler; Rack::Handler::Unicorn; end
-def rack_rainbows_handler; Rack::Handler::Rainbows; end
-
-# Selects the handler for Rack
-RSence.config[:http_server][:rack_handler] = self.method({
- 'fuzed' => :rack_fuzed_handler,
- 'webrick' => :rack_webrick_handler,
- 'ebb' => :rack_ebb_handler,
- 'thin' => :rack_thin_handler,
- 'mongrel' => :rack_mongrel_handler,
- 'unicorn' => :rack_unicorn_handler,
- 'rainbows' => :rack_rainbows_handler
-}[RSence.config[:http_server][:rack_require]]).call
-
# Transporter is the top-level handler for calls coming from the javascript COMM.Transporter.
require 'transporter/transporter'
## Broker routes requests to the correct handler
require 'http/broker'
module ::RSence
+
+ @@launch_pid = Process.pid
+
+ # Returns the pid of the process when starting up.
+ # PID is different for the forked child process(es)
+ def self.launch_pid
+ return @@launch_pid
+ end
-@@launch_pid = Process.pid
-def self.launch_pid
- return @@launch_pid
-end
-
-# The Controller module handles the damonizing
-# operations of the process referred to as +daemon+
-module Daemon
+ # The Controller module handles the damonizing
+ # operations of the process referred to as +daemon+
+ module Daemon
- # Writes the process id to disk, the pid_fn method of the daemon contains
- # the name of the pid file.
- def self.write_pid( daemon, pid )
- File.open( daemon.pid_fn, 'w' ) do |pidfile|
- pidfile.write( pid )
+ # Writes the process id to disk, the pid_fn method of the daemon contains
+ # the name of the pid file.
+ def self.write_pid( daemon, pid )
+ File.open( daemon.pid_fn, 'w' ) do |pidfile|
+ pidfile.write( pid )
+ end
end
- end
- # Reads the process id from disk, the pid_fn method of the daemon contains
- # the name of the pid file. Returns nil on errors.
- def self.read_pid( daemon )
- File.read( daemon.pid_fn ).to_i rescue nil
- end
+ # Reads the process id from disk, the pid_fn method of the daemon contains
+ # the name of the pid file. Returns nil on errors.
+ def self.read_pid( daemon )
+ File.read( daemon.pid_fn ).to_i rescue nil
+ end
- def self.responds?( daemon )
- wait_signal_response( daemon, 'USR2' )
- end
+ def self.responds?( daemon )
+ wait_signal_response( daemon, 'USR2' )
+ end
- # Reads the pid file and calls the process.
- # Returns true if the process responds, false otherwise (no process)
- def self.status( daemon )
- pid = read_pid( daemon )
- return nil if not pid
- return responds?( daemon )
- end
+ # Reads the pid file and calls the process.
+ # Returns true if the process responds, false otherwise (no process)
+ def self.status( daemon )
+ pid = read_pid( daemon )
+ return nil if not pid
+ return responds?( daemon )
+ end
- # Redirects standard input and errors to the log files
- def self.start_logging( daemon )
- outpath = "#{daemon.log_fn}.stdout"
- errpath = "#{daemon.log_fn}.stderr"
- STDOUT.reopen( outpath, (File.exist?( outpath ) ? 'a' : 'w') )
- STDOUT.sync = true
- STDERR.reopen( errpath, (File.exist?( errpath ) ? 'a' : 'w') )
- STDERR.sync = true
- end
+ # Redirects standard input and errors to the log files
+ def self.start_logging( daemon )
+ outpath = "#{daemon.log_fn}.stdout"
+ errpath = "#{daemon.log_fn}.stderr"
+ STDOUT.reopen( outpath, (File.exist?( outpath ) ? 'a' : 'w') )
+ STDOUT.sync = true
+ STDERR.reopen( errpath, (File.exist?( errpath ) ? 'a' : 'w') )
+ STDERR.sync = true
+ end
- def self.write_signal_response( daemon, signal )
- pid = Process.pid.to_s
- pid_fn = daemon.pid_fn
- RSence::SIGComm.write_signal_response( pid, pid_fn, signal )
- end
+ # Writes a signal response file containing the pid.
+ def self.write_signal_response( daemon, signal )
+ pid = Process.pid.to_s
+ pid_fn = daemon.pid_fn
+ RSence::SIGComm.write_signal_response( pid, pid_fn, signal )
+ end
- def self.delete_signal_response( daemon, signal )
- pid_fn = daemon.pid_fn
- RSence::SIGComm.delete_signal_response( pid_fn )
- end
+ # Removes a signal response file.
+ def self.delete_signal_response( daemon, signal )
+ pid_fn = daemon.pid_fn
+ RSence::SIGComm.delete_signal_response( pid_fn )
+ end
- def self.wait_signal_response( daemon, signal, timeout = 10,
- debug_pre = false, debug_suf = false, sleep_secs = 0.2 )
- pid = read_pid( daemon )
- pid_fn = daemon.pid_fn
- return RSence::SIGComm.wait_signal_response( pid, pid_fn, signal, timeout, debug_pre, debug_suf, sleep_secs )
- end
+ # Waits for a signal response.
+ def self.wait_signal_response( daemon, signal, timeout = 10,
+ debug_pre = false, debug_suf = false, sleep_secs = 0.2 )
+ pid = read_pid( daemon )
+ pid_fn = daemon.pid_fn
+ return RSence::SIGComm.wait_signal_response( pid, pid_fn, signal, timeout, debug_pre, debug_suf, sleep_secs )
+ end
- def self.trap_windows_signals( daemon )
- ['INT'].each do | signal |
- Signal.trap( signal ) do
- puts "RSence killed with signal #{signal.inspect}" if RSence.args[:verbose]
- daemon.usr1
- daemon.stop
- puts "Shutdown complete."
- exit
+ # Signal trapping for windows.
+ # The only supported POSIX signal trappable seems to be INT (CTRL-C).
+ def self.trap_windows_signals( daemon )
+ ['INT'].each do | signal |
+ Signal.trap( signal ) do
+ puts "RSence killed with signal #{signal.inspect}" if RSence.args[:verbose]
+ daemon.usr1
+ daemon.stop
+ puts "Shutdown complete."
+ exit
+ end
end
end
- end
- # Traps common kill signals
- def self.trap_signals( daemon )
+ # Traps common POSIX signals
+ def self.trap_signals( daemon )
- # Triggered with 'kill -USR1 `cat rsence.pid`'
- Signal.trap( 'USR1' ) do
- daemon.usr1
- write_signal_response( daemon, 'USR1' )
- end
- Signal.trap('USR2') do
- daemon.usr2
- write_signal_response( daemon, 'USR2' )
- end
- ['INT', 'TERM', 'KILL'].each do | signal |
- Signal.trap( signal ) do
- puts "RSence killed with signal #{signal.inspect}" if RSence.args[:verbose]
+ # Triggered with 'kill -USR1 `cat rsence.pid`'
+ Signal.trap( 'USR1' ) do
daemon.usr1
+ write_signal_response( daemon, 'USR1' )
+ end
+ Signal.trap('USR2') do
+ daemon.usr2
+ write_signal_response( daemon, 'USR2' )
+ end
+ ['INT', 'TERM', 'KILL'].each do | signal |
+ Signal.trap( signal ) do
+ puts "RSence killed with signal #{signal.inspect}" if RSence.args[:verbose]
+ daemon.usr1
+ daemon.stop
+ delete_stale_pids( daemon )
+ write_signal_response( daemon, signal )
+ puts "Shutdown complete."
+ exit
+ end
+ end
+ Signal.trap('HUP') do
daemon.stop
- delete_stale_pids( daemon )
- write_signal_response( daemon, signal )
- puts "Shutdown complete."
- exit
+ daemon.start
end
end
- Signal.trap('HUP') do
- daemon.stop
- daemon.start
- end
- end
- def self.delete_stale_pids( daemon )
- ( pid_fn_path, pid_fn_name ) = File.split( daemon.pid_fn )
- Dir.entries( pid_fn_path ).each do | item_fn |
- item_path = File.join( pid_fn_path, item_fn )
- if item_fn.start_with?( pid_fn_name ) and File.file?( item_path )
- puts "Stale pid file (#{item_fn}), removing.." if RSence.args[:verbose]
- File.delete( item_path )
+ # Removes all pid files that were left around if a process died unexpectedly.
+ def self.delete_stale_pids( daemon )
+ ( pid_fn_path, pid_fn_name ) = File.split( daemon.pid_fn )
+ Dir.entries( pid_fn_path ).each do | item_fn |
+ item_path = File.join( pid_fn_path, item_fn )
+ if item_fn.start_with?( pid_fn_name ) and File.file?( item_path )
+ puts "Stale pid file (#{item_fn}), removing.." if RSence.args[:verbose]
+ File.delete( item_path )
+ end
end
end
- end
- def self.init_pid( daemon )
- if RSence.pid_support?
- is_running = status( daemon )
- if is_running
- puts "RSence is already running."
- puts "Stop the existing process first: see 'rsence help stop'"
- if RSence.launch_pid != Process.pid
- Process.kill( 'INT', RSence.launch_pid )
+ # Creates pid file and traps signal.
+ def self.init_pid( daemon )
+ if RSence.pid_support?
+ is_running = status( daemon )
+ if is_running
+ puts "RSence is already running."
+ puts "Stop the existing process first: see 'rsence help stop'"
+ if RSence.launch_pid != Process.pid
+ Process.kill( 'INT', RSence.launch_pid )
+ end
+ exit
+ elsif not is_running
+ delete_stale_pids( daemon )
end
- exit
- elsif not is_running
- delete_stale_pids( daemon )
+ trap_signals( daemon )
+ pid = Process.pid
+ write_pid( daemon, pid )
+ return pid
+ else
+ trap_windows_signals( daemon )
+ return false
end
- trap_signals( daemon )
- pid = Process.pid
- write_pid( daemon, pid )
- return pid
- else
- trap_windows_signals( daemon )
- return false
end
- end
- def self.run( daemon )
- init_pid( daemon )
- daemon.run
- exit
- end
-
- def self.start( daemon )
- fork do
- exit if fork
+ # Inits the pid, signals and then starts the server in the foreground
+ def self.run( daemon )
init_pid( daemon )
- daemon.start
- end
- Signal.trap('INT') do
- puts "RSence startup failed. Please inspect the log and/or run in debug mode."
+ daemon.run
exit
end
- Signal.trap('TERM') do
- puts "RSence is online at http://#{daemon.addr}:#{daemon.port}/"
- exit
+
+ # Inits the pid, signals and then starts the daemon in
+ # the background and waits until the daemon sends the TERM signal.
+ def self.start( daemon )
+ fork do
+ exit if fork
+ init_pid( daemon )
+ daemon.start
+ end
+ Signal.trap('INT') do
+ puts "RSence startup failed. Please inspect the log and/or run in debug mode."
+ exit
+ end
+ Signal.trap('TERM') do
+ puts "RSence is online at http://#{daemon.addr}:#{daemon.port}/"
+ exit
+ end
+ sleep 1 while true
end
- sleep 1 while true
- end
- # Sends the USR1 signal to the process, which in turn
- # calls the save method of the daemon.
- def self.save( daemon )
- status_ = status( daemon )
- if status_
- if wait_signal_response( daemon, 'USR1', 10, 'saving.', 'saved', 0.3 )
- puts "Session data saved."
+ # Sends the USR1 signal to the process, which in turn
+ # calls the save method of the daemon.
+ def self.save( daemon )
+ status_ = status( daemon )
+ if status_
+ if wait_signal_response( daemon, 'USR1', 10, 'saving.', 'saved', 0.3 )
+ puts "Session data saved."
+ else
+ puts "Warning: saving timed out! Session data not saved."
+ end
+ elsif status_ == false
+ puts "Warning, no such process (#{pid}) running: unable to save."
+ elsif status_ == nil
+ puts "No pid file: unable to save."
else
- puts "Warning: saving timed out! Session data not saved."
+ throw "Unexpected process status: #{status_.inspect}"
end
- elsif status_ == false
- puts "Warning, no such process (#{pid}) running: unable to save."
- elsif status_ == nil
- puts "No pid file: unable to save."
- else
- throw "Unexpected process status: #{status_.inspect}"
end
- end
- # Sends the TERM signal to the process, which in turn
- # calls the stop method of the daemon
- def self.stop( daemon )#,is_restart=false)
- status_ = status( daemon )
- if status_
- if wait_signal_response( daemon, 'TERM', 10, 'killing.', 'killed', 0.3 )
- puts "RSence is terminated now."
+ # Sends the TERM signal to the process, which in turn
+ # calls the stop method of the daemon
+ def self.stop( daemon )#,is_restart=false)
+ status_ = status( daemon )
+ if status_
+ if wait_signal_response( daemon, 'TERM', 10, 'killing.', 'killed', 0.3 )
+ puts "RSence is terminated now."
+ else
+ puts "Warning: termination timed out!"
+ puts "RSence might still be running, please ensure manually."
+ end
+ elsif status_ == false
+ puts "Warning, no such process (#{read_pid(daemon)}) running."
+ elsif status_ == nil
+ puts "Warning, no pid file (process not running)."
else
- puts "Warning: termination timed out!"
- puts "RSence might still be running, please ensure manually."
+ throw "Unexpected process status: #{status_.inspect}"
end
- elsif status_ == false
- puts "Warning, no such process (#{read_pid(daemon)}) running."
- elsif status_ == nil
- puts "Warning, no pid file (process not running)."
- else
- throw "Unexpected process status: #{status_.inspect}"
end
- end
- # Main entry point called from the daemon process passing +self+ as +daemon+.
- def self.daemonize( daemon )
+ # Main entry point called from the daemon process passing +self+ as +daemon+.
+ def self.daemonize( daemon )
- # Uses the command-line tool command to decide what to do.
- case RSence.cmd
- when :run
- run( daemon )
- when :start
- start( daemon )
- when :stop
- stop( daemon )
- when :restart
- stop( daemon )
- start( daemon )
- when :save
- save( daemon )
+ # Uses the command-line tool command to decide what to do.
+ case RSence.cmd
+ when :run
+ run( daemon )
+ when :start
+ start( daemon )
+ when :stop
+ stop( daemon )
+ when :restart
+ stop( daemon )
+ start( daemon )
+ when :save
+ save( daemon )
+ end
end
- end
-end
+ end
-# Simple process control, constructed here and called from Daemon::Controller
-class HTTPDaemon
+ # Simple process control, constructed here and called from Daemon::Controller
+ class HTTPDaemon
- def run
- puts "Starting as a foreground process." if RSence.args[:verbose]
- puts "Press CTRL-C to terminate."
+ # RSence top-level run handler. Almost identical to start.
+ def run
- @transporter = Transporter.new
+ puts "Starting as a foreground process." if RSence.args[:verbose]
+ puts "Press CTRL-C to terminate."
- conf = RSence.config[:http_server]
+ @transporter = Transporter.new
- unless RSence.args[:log_fg]
- Daemon.start_logging( self )
- end
+ conf = RSence.config[:http_server]
- # This is the main http handler instance:
- @broker = Broker.start(
- @transporter,
- conf[:rack_handler],
- conf[:bind_address],
- conf[:port]
- )
+ unless RSence.args[:log_fg]
+ Daemon.start_logging( self )
+ end
- end
+ # This is the main http handler instance:
+ @broker = Broker.start(
+ @transporter,
+ conf
+ )
+
+ end
- # Returns the pid file path.
- def pid_fn
- RSence.config[:daemon][:pid_fn]
- end
+ # Returns the pid file path.
+ def pid_fn
+ RSence.config[:daemon][:pid_fn]
+ end
- # Returns the log path.
- def log_fn
- RSence.config[:daemon][:log_fn]
- end
+ # Returns the log path.
+ def log_fn
+ RSence.config[:daemon][:log_fn]
+ end
- def addr
- RSence.config[:http_server][:bind_address]
- end
+ # Returns the configured bind address
+ def addr
+ RSence.config[:http_server][:bind_address]
+ end
- def port
- RSence.config[:http_server][:port]
- end
+ # Returns the configured port.
+ def port
+ RSence.config[:http_server][:port]
+ end
- # Called by Controller#start, contains RSence-specific operations
- def start
+ # Called by Controller#start, contains RSence-specific operations
+ def start
- @transporter = Transporter.new
+ @transporter = Transporter.new
- conf = RSence.config[:http_server]
+ conf = RSence.config[:http_server]
- unless RSence.args[:log_fg]
- Daemon.start_logging( self )
- STDIN.reopen( "/dev/null" )
- end
+ unless RSence.args[:log_fg]
+ Daemon.start_logging( self )
+ STDIN.reopen( "/dev/null" )
+ end
- Process.setsid
+ Process.setsid
- # This is the main http handler instance:
- @broker = Broker.start(
- @transporter,
- conf[:rack_handler],
- conf[:bind_address],
- conf[:port]
- )
- yield @broker
+ # This is the main http handler instance:
+ @broker = Broker.start(
+ @transporter,
+ conf
+ )
+ yield @broker
- end
+ end
- # Called by Controller#stop, contains RSence-specific operations
- def stop
- @transporter.shutdown
- end
+ # Called by Controller#stop, contains RSence-specific operations
+ def stop
+ @transporter.shutdown
+ end
- # Called on USR1 signals (save data)
- def usr1
- save
- end
+ # Called on USR1 signals (save data)
+ def usr1
+ save
+ end
- # Save state
- def save
- puts "#{Time.now.strftime('%Y-%m-%d %H:%M:%S')} -- Saving state..."
- transporter_state = @transporter.online?
- @transporter.online = false
- @transporter.plugins.delegate(:flush)
- @transporter.sessions.store_sessions
- @transporter.online = transporter_state
- puts "#{Time.now.strftime('%Y-%m-%d %H:%M:%S')} -- State saved."
- end
+ # Save state
+ def save
+ puts "#{Time.now.strftime('%Y-%m-%d %H:%M:%S')} -- Saving state..."
+ transporter_state = @transporter.online?
+ @transporter.online = false
+ @transporter.plugins.delegate(:flush)
+ @transporter.sessions.store_sessions
+ @transporter.online = transporter_state
+ puts "#{Time.now.strftime('%Y-%m-%d %H:%M:%S')} -- State saved."
+ end
- # Called on USR2 signals ("Alive?")
- def usr2
- puts "#{Time.now.strftime('%Y-%m-%d %H:%M:%S')} -- RSence version #{RSence.version} is running."
- end
+ # Called on USR2 signals ("Alive?")
+ def usr2
+ puts "#{Time.now.strftime('%Y-%m-%d %H:%M:%S')} -- RSence version #{RSence.version} is running."
+ end
- # Main entry point, daemonizes itself using Controller.
- def daemonize!
- Daemon.daemonize( self )
- end
+ # Main entry point, daemonizes itself using Controller.
+ def daemonize!
+ Daemon.daemonize( self )
+ end
-end
-
+ end
end