class Daemon
Public Class Methods
daemonize(pid_file, log_file = nil, sync = true) { |log| ... }
click to toggle source
# File lib/daemon.rb, line 8 def self.daemonize(pid_file, log_file = nil, sync = true) if block_given? spawn do |send_ok, send_error| log = begin # try to lock before we kill stdin/out lock(pid_file) # close I/O disconnect(log_file, sync) rescue => error send_error.call(error) end send_ok.call yield log end # => pid, wait else # become new process group leader fence # try to lock before we kill stdin/out lock(pid_file) # close I/O disconnect(log_file, sync) # => log end end
disconnect(log_file = nil, sync = true)
click to toggle source
# File lib/daemon.rb, line 96 def self.disconnect(log_file = nil, sync = true) if log_file log = File.open(log_file, File::WRONLY | File::CREAT | File::APPEND | File::BINARY) log.sync = sync else # don't raise on STDOUT/STDERR write log = File.new('/dev/null', File::WRONLY | File::BINARY) end # disconnect STDIN.close # raise IOError on STDIN.read STDOUT.reopen log STDERR.reopen log # provide log IO return log end
fence() { || ... }
click to toggle source
# File lib/daemon.rb, line 72 def self.fence if block_given? fork do Process.setsid # become new session leader # now in child yield end # => pid else exit! 0 if fork Process.setsid # become new session leader # now in child end end
lock(pid_file)
click to toggle source
# File lib/daemon.rb, line 86 def self.lock(pid_file) pf = File.open(pid_file, File::RDWR | File::CREAT) raise LockError, pf unless pf.flock(File::LOCK_EX | File::LOCK_NB) pf.truncate(0) pf.write(Process.pid.to_s + "\n") pf.flush @pf = pf # keep it open and locked until process exits end
spawn() { | ->{ write dumpclose }| ... }
click to toggle source
# File lib/daemon.rb, line 37 def self.spawn r, w = IO.pipe pid = fence do r.close yield( ->{ w.write Marshal.dump(nil) # send OK to parent w.close }, ->(error){ w.write Marshal.dump(error) # send error to parent w.close exit 42 } ) end thr = Process.detach(pid) w.close data = r.read data.empty? and fail 'ok/error handler not called!' if error = Marshal.load(data) thr.join # wait for child to die raise error end return pid, thr ensure w.close unless w.closed? r.close end