Module: Daemonizable

Included in:
RaadTotem::Runner
Defined in:
lib/raad_totem/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
51
52
# File 'lib/raad_totem/unix_daemon.rb', line 29

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

  if RaadTotem.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
    spanw_options = [RaadTotem.ruby_path].concat(RaadTotem.ruby_options)
    spanw_options << $0
    spanw_options.concat(argv.map{|arg| arg == 'start' ? 'post_fork' : arg})
    Spoon.spawnp(*spanw_options)
  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



92
93
94
95
96
97
98
99
100
101
# File 'lib/raad_totem/unix_daemon.rb', line 92

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_totem/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



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/raad_totem/unix_daemon.rb', line 54

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



103
104
105
106
107
108
109
# File 'lib/raad_totem/unix_daemon.rb', line 103

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

#remove_pid_fileObject



111
112
113
# File 'lib/raad_totem/unix_daemon.rb', line 111

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

#remove_stale_pid_fileObject



120
121
122
123
124
125
126
127
128
129
# File 'lib/raad_totem/unix_daemon.rb', line 120

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



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

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



115
116
117
118
# File 'lib/raad_totem/unix_daemon.rb', line 115

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