Class: Procodile::Instance
- Inherits:
-
Object
- Object
- Procodile::Instance
- Defined in:
- lib/procodile/instance.rb
Instance Attribute Summary collapse
-
#id ⇒ Object
readonly
Returns the value of attribute id.
-
#pid ⇒ Object
Returns the value of attribute pid.
-
#port ⇒ Object
readonly
Returns the value of attribute port.
-
#process ⇒ Object
Returns the value of attribute process.
-
#tag ⇒ Object
readonly
Returns the value of attribute tag.
Instance Method Summary collapse
-
#add_respawn ⇒ Object
Increment the counter of respawns for this process.
-
#allocate_port ⇒ Object
Find a port number for this instance to listen on.
-
#can_respawn? ⇒ Boolean
Can this process be respawned if needed?.
-
#check(options = {}) ⇒ Object
Check the status of this process and handle as appropriate.
-
#description ⇒ Object
Return a description for this instance.
-
#environment_variables ⇒ Object
Return an array of environment variables that should be set.
-
#failed? ⇒ Boolean
Has this failed?.
-
#initialize(supervisor, process, id) ⇒ Instance
constructor
A new instance of Instance.
-
#on_stop ⇒ Object
A method that will be called when this instance has been stopped and it isn’t going to be started again.
-
#pid_file_path ⇒ Object
Return the path to this instance’s PID file.
-
#pid_from_file ⇒ Object
Return the PID that is in the instances process PID file.
-
#respawns ⇒ Object
Return the number of times this process has been respawned in the last hour.
-
#restart ⇒ Object
Retarts the process using the appropriate method from the process configuraiton.
-
#running? ⇒ Boolean
Is this process running? Pass an option to check the given PID instead of the instance.
-
#start ⇒ Object
Start a new instance of this process.
-
#status ⇒ Object
Return the status of this instance.
-
#stop ⇒ Object
Send this signal the signal to stop and mark the instance in a state that tells us that we want it to be stopped.
-
#stopped? ⇒ Boolean
Is this stopped?.
-
#stopping? ⇒ Boolean
Is this instance supposed to be stopping/be stopped?.
-
#tidy ⇒ Object
Tidy up when this process isn’t needed any more.
-
#to_hash ⇒ Object
Return this instance as a hash.
-
#update_pid ⇒ Object
Update the locally cached PID from that stored on the file system.
Constructor Details
#initialize(supervisor, process, id) ⇒ Instance
Returns a new instance of Instance.
12 13 14 15 16 17 18 |
# File 'lib/procodile/instance.rb', line 12 def initialize(supervisor, process, id) @supervisor = supervisor @process = process @id = id @respawns = 0 @started_at = nil end |
Instance Attribute Details
#id ⇒ Object (readonly)
Returns the value of attribute id.
7 8 9 |
# File 'lib/procodile/instance.rb', line 7 def id @id end |
#pid ⇒ Object
Returns the value of attribute pid.
6 7 8 |
# File 'lib/procodile/instance.rb', line 6 def pid @pid end |
#port ⇒ Object (readonly)
Returns the value of attribute port.
10 11 12 |
# File 'lib/procodile/instance.rb', line 10 def port @port end |
#process ⇒ Object
Returns the value of attribute process.
8 9 10 |
# File 'lib/procodile/instance.rb', line 8 def process @process end |
#tag ⇒ Object (readonly)
Returns the value of attribute tag.
9 10 11 |
# File 'lib/procodile/instance.rb', line 9 def tag @tag end |
Instance Method Details
#add_respawn ⇒ Object
Increment the counter of respawns for this process
285 286 287 288 289 290 291 292 |
# File 'lib/procodile/instance.rb', line 285 def add_respawn if @last_respawn && @last_respawn < (Time.now - @process.respawn_window) @respawns = 1 else @last_respawn = Time.now @respawns += 1 end end |
#allocate_port ⇒ Object
Find a port number for this instance to listen on. We just check that nothing is already listening on it. The process is expected to take it straight away if it wants it.
315 316 317 318 319 320 321 322 323 324 325 326 |
# File 'lib/procodile/instance.rb', line 315 def allocate_port until @port possible_port = rand(10000) + 20000 begin server = TCPServer.new('127.0.0.1', possible_port) server.close return @port = possible_port rescue # Nah. end end end |
#can_respawn? ⇒ Boolean
Can this process be respawned if needed?
267 268 269 |
# File 'lib/procodile/instance.rb', line 267 def can_respawn? !stopping? && (respawns + 1) <= @process.max_respawns end |
#check(options = {}) ⇒ Object
Check the status of this process and handle as appropriate.
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 |
# File 'lib/procodile/instance.rb', line 234 def check( = {}) return if failed? if self.running? # Everything is OK. The process is running. true else # If the process isn't running any more, update the PID in our memory from # the file in case the process has changed itself. return check if update_pid if @supervisor.allow_respawning? if can_respawn? Procodile.log(@process.log_color, description, "Process has stopped. Respawning...") start add_respawn elsif respawns >= @process.max_respawns Procodile.log(@process.log_color, description, "\e[41;37mWarning:\e[0m\e[31m this process has been respawned #{respawns} times and keeps dying.\e[0m") Procodile.log(@process.log_color, description, "It will not be respawned automatically any longer and will no longer be managed.".color(31)) @failed = Time.now tidy end else Procodile.log(@process.log_color, description, "Process has stopped. Respawning not available.") @failed = Time.now tidy end end end |
#description ⇒ Object
Return a description for this instance
23 24 25 |
# File 'lib/procodile/instance.rb', line 23 def description "#{@process.name}.#{@id}" end |
#environment_variables ⇒ Object
Return an array of environment variables that should be set
47 48 49 50 51 52 53 54 55 |
# File 'lib/procodile/instance.rb', line 47 def environment_variables vars = @process.environment_variables.merge({ 'PROC_NAME' => self.description, 'PID_FILE' => self.pid_file_path, 'APP_ROOT' => @process.config.root }) vars['PORT'] = @port.to_s if @port vars end |
#failed? ⇒ Boolean
Has this failed?
145 146 147 |
# File 'lib/procodile/instance.rb', line 145 def failed? @failed ? true : false end |
#on_stop ⇒ Object
A method that will be called when this instance has been stopped and it isn’t going to be started again
168 169 170 171 172 |
# File 'lib/procodile/instance.rb', line 168 def on_stop @started_at = nil @stopped = true tidy end |
#pid_file_path ⇒ Object
Return the path to this instance’s PID file
60 61 62 |
# File 'lib/procodile/instance.rb', line 60 def pid_file_path File.join(@process.config.pid_root, "#{description}.pid") end |
#pid_from_file ⇒ Object
Return the PID that is in the instances process PID file
67 68 69 70 71 72 73 74 |
# File 'lib/procodile/instance.rb', line 67 def pid_from_file if File.exist?(pid_file_path) pid = File.read(pid_file_path) pid.length > 0 ? pid.strip.to_i : nil else nil end end |
#respawns ⇒ Object
Return the number of times this process has been respawned in the last hour
274 275 276 277 278 279 280 |
# File 'lib/procodile/instance.rb', line 274 def respawns if @respawns.nil? || @last_respawn.nil? || @last_respawn < (Time.now - @process.respawn_window) 0 else @respawns end end |
#restart ⇒ Object
Retarts the process using the appropriate method from the process configuraiton
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 |
# File 'lib/procodile/instance.rb', line 185 def restart Procodile.log(@process.log_color, description, "Restarting using #{@process.restart_mode} mode") update_pid case @process.restart_mode when 'usr1', 'usr2' if running? ::Process.kill(@process.restart_mode.upcase, @pid) @tag = @supervisor.tag if @supervisor.tag Procodile.log(@process.log_color, description, "Sent #{@process.restart_mode.upcase} signal to process #{@pid}") else Procodile.log(@process.log_color, description, "Process not running already. Starting it.") on_stop @process.create_instance(@supervisor).start end self when 'start-term' new_instance = @process.create_instance(@supervisor) new_instance.start stop new_instance when 'term-start' stop new_instance = @process.create_instance(@supervisor) Thread.new do sleep 0.5 while running? new_instance.start end new_instance end end |
#running? ⇒ Boolean
Is this process running? Pass an option to check the given PID instead of the instance
79 80 81 82 83 84 85 86 87 |
# File 'lib/procodile/instance.rb', line 79 def running? if @pid ::Process.getpgid(@pid) ? true : false else false end rescue Errno::ESRCH false end |
#start ⇒ Object
Start a new instance of this process
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/procodile/instance.rb', line 92 def start if stopping? Procodile.log(@process.log_color, description, "Process is stopped/stopping therefore cannot be started again.") return false end update_pid if running? Procodile.log(@process.log_color, description, "Already running with PID #{@pid}") nil else if @process.proxy? && @supervisor.tcp_proxy allocate_port end if self.process.log_path log_destination = File.open(self.process.log_path, 'a') io = nil else reader, writer = IO.pipe log_destination = writer io = reader end @tag = @supervisor.tag.dup if @supervisor.tag Dir.chdir(@process.config.root) @pid = ::Process.spawn(environment_variables, @process.command, :out => log_destination, :err => log_destination, :pgroup => true) log_destination.close File.open(pid_file_path, 'w') { |f| f.write(@pid.to_s + "\n") } @supervisor.add_instance(self, io) ::Process.detach(@pid) Procodile.log(@process.log_color, description, "Started with PID #{@pid}" + (@tag ? " (tagged with #{@tag})" : '')) @started_at = Time.now end end |
#status ⇒ Object
Return the status of this instance
30 31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/procodile/instance.rb', line 30 def status if stopped? 'Stopped' elsif stopping? 'Stopping' elsif running? 'Running' elsif failed? 'Failed' else 'Unknown' end end |
#stop ⇒ Object
Send this signal the signal to stop and mark the instance in a state that tells us that we want it to be stopped.
153 154 155 156 157 158 159 160 161 162 |
# File 'lib/procodile/instance.rb', line 153 def stop @stopping = Time.now update_pid if self.running? Procodile.log(@process.log_color, description, "Sending #{@process.term_signal} to #{@pid}") ::Process.kill(@process.term_signal, pid) else Procodile.log(@process.log_color, description, "Process already stopped") end end |
#stopped? ⇒ Boolean
Is this stopped?
138 139 140 |
# File 'lib/procodile/instance.rb', line 138 def stopped? @stopped || false end |
#stopping? ⇒ Boolean
Is this instance supposed to be stopping/be stopped?
131 132 133 |
# File 'lib/procodile/instance.rb', line 131 def stopping? @stopping ? true : false end |
#tidy ⇒ Object
Tidy up when this process isn’t needed any more
177 178 179 180 |
# File 'lib/procodile/instance.rb', line 177 def tidy FileUtils.rm_f(self.pid_file_path) Procodile.log(@process.log_color, description, "Removed PID file") end |
#to_hash ⇒ Object
Return this instance as a hash
297 298 299 300 301 302 303 304 305 306 307 308 |
# File 'lib/procodile/instance.rb', line 297 def to_hash { :description => self.description, :pid => self.pid, :respawns => self.respawns, :status => self.status, :running => self.running?, :started_at => @started_at ? @started_at.to_i : nil, :tag => self.tag, :port => @port } end |
#update_pid ⇒ Object
Update the locally cached PID from that stored on the file system.
219 220 221 222 223 224 225 226 227 228 229 |
# File 'lib/procodile/instance.rb', line 219 def update_pid pid_from_file = self.pid_from_file if pid_from_file && pid_from_file != @pid @pid = pid_from_file @started_at = File.mtime(self.pid_file_path) Procodile.log(@process.log_color, description, "PID file changed. Updated pid to #{@pid}") true else false end end |