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_homePath to the daemon’s home -
#daemon_nameName of the daemon -
#daemon_loopOne loop of the daemon to be repeatedly called -
#daemon_first_loopTo 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
taskwith 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
pidis 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
pidis still alive, callterminateotherwise. -
#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
pidif it does. - #write_alive_file ⇒ Object
Instance Attribute Details
#declare_alive_pid ⇒ Object (readonly)
Process ID of the forked process declaring the daemon alive
14 15 16 |
# File 'lib/miga/common/with_daemon.rb', line 14 def declare_alive_pid @declare_alive_pid end |
#loop_i ⇒ Object (readonly)
Loop counter
17 18 19 |
# File 'lib/miga/common/with_daemon.rb', line 17 def loop_i @loop_i end |
Instance Method Details
#active? ⇒ Boolean
Is the daemon active?
47 48 49 50 |
# File 'lib/miga/common/with_daemon.rb', line 47 def active? return false unless File.exist? alive_file last_alive > Time.now - 60 end |
#alive_file ⇒ Object
31 32 33 |
# File 'lib/miga/common/with_daemon.rb', line 31 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.
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/miga/common/with_daemon.rb', line 124 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_homeDaemon’s home does not exist -
:no_process_aliveProcess is not currently running -
:termination_fileFound termination file
71 72 73 74 75 76 77 78 79 80 81 |
# 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.
112 113 114 115 116 117 |
# File 'lib/miga/common/with_daemon.rb', line 112 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
184 185 186 187 188 189 190 191 192 |
# File 'lib/miga/common/with_daemon.rb', line 184 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?
41 42 43 |
# File 'lib/miga/common/with_daemon.rb', line 41 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.
166 167 168 |
# File 'lib/miga/common/with_daemon.rb', line 166 def launch_daemon_proc() Daemons.run_proc("#{daemon_name}", ) { while in_loop; end } end |
#output_file ⇒ Object
23 24 25 |
# File 'lib/miga/common/with_daemon.rb', line 23 def output_file File.join(daemon_home, "#{daemon_name}.output") end |
#pid_file ⇒ Object
19 20 21 |
# File 'lib/miga/common/with_daemon.rb', line 19 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.
90 91 92 93 94 95 96 |
# File 'lib/miga/common/with_daemon.rb', line 90 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
178 179 180 |
# File 'lib/miga/common/with_daemon.rb', line 178 def run(opts = [], wait = true) daemon(:run, opts, wait) end |
#start(opts = [], wait = true) ⇒ Object
Initializes the daemon with opts
172 173 174 |
# File 'lib/miga/common/with_daemon.rb', line 172 def start(opts = [], wait = true) daemon(:start, opts, wait) end |
#status(opts = [], wait = true) ⇒ Object
Returns the status of the daemon with opts
156 157 158 159 160 161 162 |
# File 'lib/miga/common/with_daemon.rb', line 156 def status(opts = [], wait = true) if active? say "Running with pid #{File.read(pid_file)}" else say 'Not running' end end |
#stop(opts = [], wait = true) ⇒ Object
Stops the daemon with opts
143 144 145 146 147 148 149 150 151 152 |
# File 'lib/miga/common/with_daemon.rb', line 143 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.
196 197 198 199 200 201 202 |
# File 'lib/miga/common/with_daemon.rb', line 196 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
27 28 29 |
# File 'lib/miga/common/with_daemon.rb', line 27 def terminate_file File.join(daemon_home, 'terminate-daemon') end |
#terminated_file ⇒ Object
35 36 37 |
# File 'lib/miga/common/with_daemon.rb', line 35 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
101 102 103 104 105 106 107 108 |
# File 'lib/miga/common/with_daemon.rb', line 101 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
83 84 85 |
# File 'lib/miga/common/with_daemon.rb', line 83 def write_alive_file File.open(alive_file, 'w') { |fh| fh.print Time.now.to_s } end |