Class: Workhorse::Daemon
- Inherits:
-
Object
- Object
- Workhorse::Daemon
- Defined in:
- lib/workhorse/daemon.rb
Overview
Daemon class for managing multiple worker processes. Provides functionality to start, stop, restart, and monitor worker processes through a simple Ruby DSL.
Defined Under Namespace
Classes: ShellHandler, Worker
Instance Attribute Summary collapse
-
#workers ⇒ Array<Worker>
readonly
Array of defined workers.
Instance Method Summary collapse
-
#initialize(pidfile: nil, quiet: false) {|ScopedEnv| ... } ⇒ Daemon
constructor
Creates a new daemon instance.
-
#restart ⇒ Integer
Restarts all workers by stopping and then starting them.
-
#restart_logging ⇒ Integer
Sends HUP signal to all workers to restart their logging.
-
#start(quiet: false) ⇒ Integer
Starts all defined workers.
-
#status(quiet: false) ⇒ Integer
Checks the status of all workers.
-
#stop(kill = false, quiet: false) ⇒ Integer
Stops all running workers.
-
#watch ⇒ Integer
Watches workers and starts them if they’re not running.
-
#worker(name = 'Job Worker') { ... } ⇒ void
Defines a worker process.
Constructor Details
#initialize(pidfile: nil, quiet: false) {|ScopedEnv| ... } ⇒ Daemon
Creates a new daemon instance.
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/workhorse/daemon.rb', line 43 def initialize(pidfile: nil, quiet: false, &_block) @pidfile = pidfile @quiet = quiet @workers = [] yield ScopedEnv.new(self, [:worker]) @count = @workers.count fail 'No workers are defined.' if @count < 1 FileUtils.mkdir_p('tmp/pids') if @pidfile.nil? @pidfile = @count > 1 ? 'tmp/pids/workhorse.%i.pid' : 'tmp/pids/workhorse.pid' elsif @count > 1 && !@pidfile.include?('%s') fail 'Pidfile must include placeholder "%s" for worker id when specifying a count > 1.' elsif @count == 0 && @pidfile.include?('%s') fail 'Pidfile must not include placeholder "%s" for worker id when specifying a count of 1.' end end |
Instance Attribute Details
#workers ⇒ Array<Worker> (readonly)
Returns Array of defined workers.
35 36 37 |
# File 'lib/workhorse/daemon.rb', line 35 def workers @workers end |
Instance Method Details
#restart ⇒ Integer
Restarts all workers by stopping and then starting them.
188 189 190 191 |
# File 'lib/workhorse/daemon.rb', line 188 def restart stop return start end |
#restart_logging ⇒ Integer
Sends HUP signal to all workers to restart their logging. Useful for log rotation without full process restart.
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
# File 'lib/workhorse/daemon.rb', line 197 def restart_logging code = 0 for_each_worker do |worker| _pid_file, pid, active = read_pid(worker) next unless pid && active begin Process.kill 'HUP', pid puts "Worker (#{worker.name}) ##{worker.id}: Sent signal for restart-logging" rescue Errno::ESRCH warn "Worker (#{worker.name}) ##{worker.id}: Could not send signal for restart-logging, process not found" code = 2 end end return code end |
#start(quiet: false) ⇒ Integer
Starts all defined workers.
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
# File 'lib/workhorse/daemon.rb', line 78 def start(quiet: false) code = 0 # Holds messages in format [[<message>, <severity>]] = [] for_each_worker do |worker| pid_file, pid, active = read_pid(worker) if pid_file && pid && active << ["Worker ##{worker.id} (#{worker.name}): Already started (PID #{pid})", 2] unless quiet code = 2 elsif pid_file File.delete pid_file shutdown_file = pid ? Workhorse::Worker.shutdown_file_for(pid) : nil shutdown_file = nil if shutdown_file && !File.exist?(shutdown_file) << ["Worker ##{worker.id} (#{worker.name}): Starting (stale pid file)", 1] unless quiet || shutdown_file start_worker worker FileUtils.rm(shutdown_file) if shutdown_file else << ["Worker ##{worker.id} (#{worker.name}): Starting", 1] unless quiet start_worker worker end end if .any? min = .min_by(&:last)[1] # Only print messages if there is at least one message with severity 1 if min == 1 .each { |(, _severity)| warn } end end return code end |
#status(quiet: false) ⇒ Integer
Checks the status of all workers.
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
# File 'lib/workhorse/daemon.rb', line 147 def status(quiet: false) code = 0 for_each_worker do |worker| pid_file, pid, active = read_pid(worker) if pid_file && pid && active puts "Worker ##{worker.id} (#{worker.name}): Running" unless quiet elsif pid_file warn "Worker ##{worker.id} (#{worker.name}): Not running (stale PID file)" unless quiet code = 2 else warn "Worker ##{worker.id} (#{worker.name}): Not running" unless quiet code = 2 end end return code end |
#stop(kill = false, quiet: false) ⇒ Integer
Stops all running workers.
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/workhorse/daemon.rb', line 122 def stop(kill = false, quiet: false) code = 0 for_each_worker do |worker| pid_file, pid, active = read_pid(worker) if pid_file && pid && active puts "Worker (#{worker.name}) ##{worker.id}: Stopping" unless quiet stop_worker pid_file, pid, kill: kill elsif pid_file File.delete pid_file puts "Worker (#{worker.name}) ##{worker.id}: Already stopped (stale PID file)" unless quiet else warn "Worker (#{worker.name}) ##{worker.id}: Already stopped" unless quiet code = 2 end end return code end |
#watch ⇒ Integer
Watches workers and starts them if they’re not running. In Rails environments, respects the tmp/stop.txt file.
171 172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/workhorse/daemon.rb', line 171 def watch if defined?(Rails) should_be_running = !File.exist?(Rails.root.join('tmp/stop.txt')) else should_be_running = true end if should_be_running && status(quiet: true) != 0 return start(quiet: Workhorse.silence_watcher) else return 0 end end |