Module: Daemonizable

Included in:
Raad::Runner
Defined in:
lib/raad/unix_daemon.rb

Overview

module Daemonizable requires that the including class defines the @pid_file instance variable

Instance Method Summary collapse

Instance Method Details

#daemonize(argv, name, stdout_file = nil) ⇒ Object



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/raad/unix_daemon.rb', line 29

def daemonize(argv, name, stdout_file = nil)
  remove_stale_pid_file
  pwd = Dir.pwd

  if Raad.jruby?
    # in jruby the process is to posix-spawn a new process and re execute ourself using Spoon.
    # swap command 'start' for 'post_fork' to signal the second exec
    spawn_argv = argv.map{|arg| arg == 'start' ? 'post_fork' : arg}
    Spoon.spawnp(Raad.ruby_path, $0, *spawn_argv)
  else
    # do the double fork dance
    Process.fork do
      Process.setsid
      exit if fork # exit parent
 
      Dir.chdir(pwd)
      post_fork_setup(name, stdout_file)

      yield
    end
  end
end

#force_kill_and_remove_pid_file(pid) ⇒ Object



90
91
92
93
94
95
96
97
98
99
# File 'lib/raad/unix_daemon.rb', line 90

def force_kill_and_remove_pid_file(pid)
  puts(">> sending KILL signal to process #{pid}")
  Process.kill("KILL", pid)
  remove_pid_file
  true
rescue Errno::ESRCH # No such process
  puts(">> can't send KILL, no such process #{pid}")
  remove_pid_file
  false
end

#pidObject



25
26
27
# File 'lib/raad/unix_daemon.rb', line 25

def pid
  File.exist?(@pid_file) ? open(@pid_file).read.to_i : nil
end

#post_fork_setup(name, stdout_file = nil) ⇒ Object



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/raad/unix_daemon.rb', line 52

def post_fork_setup(name, stdout_file = nil)
  $0 = name # set process name, does not work with jruby

  File.umask(0000) # file mode creation mask to 000 to allow creation of files with any required permission late
  write_pid_file

  # redirect stdin, stdout, stderr
  STDIN.reopen('/dev/null')
  stdout_file ? STDOUT.reopen(stdout_file, "a") : STDOUT.reopen('/dev/null', 'a')
  STDERR.reopen(STDOUT)

  at_exit do
    remove_pid_file
  end
end

#read_pid_fileObject



101
102
103
104
105
106
107
# File 'lib/raad/unix_daemon.rb', line 101

def read_pid_file
  if File.file?(@pid_file) && pid = File.read(@pid_file)
    pid.to_i
  else
    nil
  end
end

#remove_pid_fileObject



109
110
111
# File 'lib/raad/unix_daemon.rb', line 109

def remove_pid_file
  File.delete(@pid_file) if @pid_file && File.exists?(@pid_file)
end

#remove_stale_pid_fileObject



118
119
120
121
122
123
124
125
126
127
# File 'lib/raad/unix_daemon.rb', line 118

def remove_stale_pid_file
  if File.exist?(@pid_file)
    if pid && Process.running?(pid)
      raise PidFileExist, "#{@pid_file} exists and process #{pid} is runnig. stop the process or delete #{@pid_file}"
    else
      puts(">> deleting stale pid file #{@pid_file}")
      remove_pid_file
    end
  end
end

#send_signal(signal, timeout = 60) ⇒ Object



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/raad/unix_daemon.rb', line 68

def send_signal(signal, timeout = 60)
  if pid = read_pid_file
    puts(">> sending #{signal} signal to process #{pid}")
    Process.kill(signal, pid)
    Timeout.timeout(timeout) do
      sleep 0.1 while Process.running?(pid)
    end
    true
  else
    puts(">> can't stop process, no pid found in #{@pid_file}")
    false
  end
rescue Timeout::Error
  force_kill_and_remove_pid_file(pid)
rescue Interrupt
  force_kill_and_remove_pid_file(pid)
rescue Errno::ESRCH # No such process
  puts(">> can't stop process, no such process #{pid}")
  remove_pid_file
  false
end

#write_pid_fileObject



113
114
115
116
# File 'lib/raad/unix_daemon.rb', line 113

def write_pid_file
  open(@pid_file,"w") { |f| f.write(Process.pid) }
  File.chmod(0644, @pid_file)
end