Module: MiGA::Common::WithDaemon
Overview
Helper module with specific functions to handle objects that have daemons. The class including it must extend MiGA::Common::WithDaemonClass and define:
-
#daemon_home
Path to the daemon’s home -
#daemon_name
Name of the daemon -
#daemon_loop
One loop of the daemon to be repeatedly called -
#daemon_first_loop
To be executed before the first call to#daemon_loop
Instance Attribute Summary collapse
-
#declare_alive_pid ⇒ Object
readonly
Process ID of the forked process declaring the daemon alive.
-
#loop_i ⇒ Object
readonly
Loop counter.
Instance Method Summary collapse
-
#active? ⇒ Boolean
Is the daemon active?.
- #alive_file ⇒ Object
-
#daemon(task, opts = [], wait = true) ⇒ Object
Launches the
task
with optionsopts
(as command-line arguments) and returns the process ID as an Integer. -
#declare_alive ⇒ Object
Tell the world that you’re alive.
-
#declare_alive_loop(pid = Process.ppid) ⇒ Object
Loop checking if the process with PID
pid
is still alive. -
#default_options ⇒ Object
Returns Hash containing the default options for the daemon.
-
#in_loop ⇒ Object
One loop, returns a boolean indicating if the execution should continue.
-
#last_alive ⇒ Object
When was the daemon last seen active?.
-
#launch_daemon_proc(options) ⇒ Object
Pass daemon options to
Daemons
. - #output_file ⇒ Object
- #pid_file ⇒ Object
-
#process_alive?(pid) ⇒ Boolean
Check if the process with PID
pid
is still alive, callterminate
otherwise. -
#run(opts = [], wait = true) ⇒ Object
Initializes the daemon on top with
opts
. -
#start(opts = [], wait = true) ⇒ Object
Initializes the daemon with
opts
. -
#status(opts = [], wait = true) ⇒ Object
Returns the status of the daemon with
opts
. -
#stop(opts = [], wait = true) ⇒ Object
Stops the daemon with
opts
. -
#terminate ⇒ Object
Declares a daemon termination.
- #terminate_file ⇒ Object
- #terminated_file ⇒ Object
-
#termination_file?(pid) ⇒ Boolean
Check if a termination file exists and terminate process with PID
pid
if it does. - #write_alive_file ⇒ Object
Instance Attribute Details
#declare_alive_pid ⇒ Object (readonly)
Process ID of the forked process declaring the daemon alive
13 14 15 |
# File 'lib/miga/common/with_daemon.rb', line 13 def declare_alive_pid @declare_alive_pid end |
#loop_i ⇒ Object (readonly)
Loop counter
16 17 18 |
# File 'lib/miga/common/with_daemon.rb', line 16 def loop_i @loop_i end |
Instance Method Details
#active? ⇒ Boolean
Is the daemon active?
46 47 48 49 50 |
# File 'lib/miga/common/with_daemon.rb', line 46 def active? return false unless File.exist? alive_file (last_alive || Time.new(0)) > Time.now - 60 end |
#alive_file ⇒ Object
30 31 32 |
# File 'lib/miga/common/with_daemon.rb', line 30 def alive_file self.class.alive_file(daemon_home) end |
#daemon(task, opts = [], wait = true) ⇒ Object
Launches the task
with options opts
(as command-line arguments) and returns the process ID as an Integer. If wait
it waits for the process to complete, immediately returns otherwise. Supported tasks: start, run, stop, status.
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/miga/common/with_daemon.rb', line 127 def daemon(task, opts = [], wait = true) MiGA::MiGA.DEBUG "#{self.class}#daemon #{task} #{opts}" task = task.to_sym raise "Unsupported task: #{task}" unless respond_to? task return send(task, opts, wait) unless %i[start run].include? task # start & run: = opts.unshift(task.to_s) [:ARGV] = opts # This additional degree of separation below was introduced so the Daemons # package doesn't kill the parent process in workflows. pid = fork { launch_daemon_proc() } Process.wait(pid) if wait pid end |
#declare_alive ⇒ Object
Tell the world that you’re alive.
54 55 56 57 58 59 60 61 |
# File 'lib/miga/common/with_daemon.rb', line 54 def declare_alive if active? raise "Trying to declare alive an active daemon, if you think this is a" \ " mistake please remove #{alive_file} or try again in 1 minute" end @declare_alive_pid = fork { declare_alive_loop } sleep(1) # <- to wait for the process check end |
#declare_alive_loop(pid = Process.ppid) ⇒ Object
Loop checking if the process with PID pid
is still alive. By default, the parent process. Do not use directly, use declare_alive
instead. Returns a symbol indicating the reason to stop:
-
:no_home
Daemon’s home does not exist -
:no_process_alive
Process is not currently running -
:termination_file
Found termination file
71 72 73 74 75 76 77 78 79 80 81 82 83 |
# File 'lib/miga/common/with_daemon.rb', line 71 def declare_alive_loop(pid = Process.ppid) i = -1 loop do i += 1 return :no_home unless Dir.exist? daemon_home return :no_process_alive unless process_alive? pid write_alive_file if i % 30 == 0 return :termination_file if termination_file? pid sleep(1) end end |
#default_options ⇒ Object
Returns Hash containing the default options for the daemon.
115 116 117 118 119 120 |
# File 'lib/miga/common/with_daemon.rb', line 115 def { dir_mode: :normal, dir: daemon_home, multiple: false, log_output: true, stop_proc: :terminate } end |
#in_loop ⇒ Object
One loop, returns a boolean indicating if the execution should continue
187 188 189 190 191 192 193 194 195 |
# File 'lib/miga/common/with_daemon.rb', line 187 def in_loop if loop_i.nil? declare_alive daemon_first_loop @loop_i = -1 end @loop_i += 1 daemon_loop end |
#last_alive ⇒ Object
When was the daemon last seen active?
40 41 42 |
# File 'lib/miga/common/with_daemon.rb', line 40 def last_alive self.class.last_alive(daemon_home) end |
#launch_daemon_proc(options) ⇒ Object
Pass daemon options to Daemons
. Do not use directly, use daemon
instead.
169 170 171 |
# File 'lib/miga/common/with_daemon.rb', line 169 def launch_daemon_proc() Daemons.run_proc("#{daemon_name}", ) { while in_loop; end } end |
#output_file ⇒ Object
22 23 24 |
# File 'lib/miga/common/with_daemon.rb', line 22 def output_file File.join(daemon_home, "#{daemon_name}.output") end |
#pid_file ⇒ Object
18 19 20 |
# File 'lib/miga/common/with_daemon.rb', line 18 def pid_file File.join(daemon_home, "#{daemon_name}.pid") end |
#process_alive?(pid) ⇒ Boolean
Check if the process with PID pid
is still alive, call terminate
otherwise.
92 93 94 95 96 97 98 |
# File 'lib/miga/common/with_daemon.rb', line 92 def process_alive?(pid) Process.kill(0, pid) true rescue Errno::ESRCH, Errno::EPERM, Errno::ENOENT terminate false end |
#run(opts = [], wait = true) ⇒ Object
Initializes the daemon on top with opts
181 182 183 |
# File 'lib/miga/common/with_daemon.rb', line 181 def run(opts = [], wait = true) daemon(:run, opts, wait) end |
#start(opts = [], wait = true) ⇒ Object
Initializes the daemon with opts
175 176 177 |
# File 'lib/miga/common/with_daemon.rb', line 175 def start(opts = [], wait = true) daemon(:start, opts, wait) end |
#status(opts = [], wait = true) ⇒ Object
Returns the status of the daemon with opts
159 160 161 162 163 164 165 |
# File 'lib/miga/common/with_daemon.rb', line 159 def status(opts = [], wait = true) if active? say "Running with pid #{File.size?(pid_file) ? File.read(pid_file) : '?'}" else say 'Not running' end end |
#stop(opts = [], wait = true) ⇒ Object
Stops the daemon with opts
146 147 148 149 150 151 152 153 154 155 |
# File 'lib/miga/common/with_daemon.rb', line 146 def stop(opts = [], wait = true) if active? say 'Sending termination message' FileUtils.touch(terminate_file) sleep(0.5) while active? if wait File.unlink(pid_file) if File.exist?(pid_file) else say 'No running instances' end end |
#terminate ⇒ Object
Declares a daemon termination. Do not use, directly, use #stop instead.
199 200 201 202 203 204 205 |
# File 'lib/miga/common/with_daemon.rb', line 199 def terminate unless declare_alive_pid.nil? Process.kill(9, declare_alive_pid) @declare_alive_pid = nil end File.rename(alive_file, terminated_file) if File.exist? alive_file end |
#terminate_file ⇒ Object
26 27 28 |
# File 'lib/miga/common/with_daemon.rb', line 26 def terminate_file File.join(daemon_home, 'terminate-daemon') end |
#terminated_file ⇒ Object
34 35 36 |
# File 'lib/miga/common/with_daemon.rb', line 34 def terminated_file self.class.terminated_file(daemon_home) end |
#termination_file?(pid) ⇒ Boolean
Check if a termination file exists and terminate process with PID pid
if it does. Do not kill any process if pid
is nil
103 104 105 106 107 108 109 110 111 |
# File 'lib/miga/common/with_daemon.rb', line 103 def termination_file?(pid) return false unless File.exist? terminate_file say 'Found termination file, terminating' File.unlink(terminate_file) terminate Process.kill(9, pid) unless pid.nil? true end |
#write_alive_file ⇒ Object
85 86 87 |
# File 'lib/miga/common/with_daemon.rb', line 85 def write_alive_file File.open(alive_file, 'w') { |fh| fh.print Time.now.to_s } end |