Class: Foreman::Engine
- Inherits:
-
Object
- Object
- Foreman::Engine
- Defined in:
- lib/foreman/engine.rb
Direct Known Subclasses
Defined Under Namespace
Classes: CLI
Constant Summary collapse
- HANDLED_SIGNALS =
The signals that the engine cares about.
[ :TERM, :INT, :HUP ]
Instance Attribute Summary collapse
-
#env ⇒ Object
readonly
Returns the value of attribute env.
-
#options ⇒ Object
readonly
Returns the value of attribute options.
-
#processes ⇒ Object
readonly
Returns the value of attribute processes.
Instance Method Summary collapse
-
#base_port ⇒ Object
Get the base port for this foreman instance.
-
#clear ⇒ Object
Clear the processes registered to this
Engine
. -
#each_process ⇒ Object
Yield each
Process
in order. -
#environment ⇒ Object
deprecated.
-
#formation ⇒ Object
Get the process formation.
-
#handle_hangup ⇒ Object
Handle a HUP signal.
-
#handle_interrupt ⇒ Object
Handle an INT signal.
-
#handle_signal(sig) ⇒ Object
Invoke the real handler for signal
sig
. -
#handle_term_signal ⇒ Object
Handle a TERM signal.
-
#initialize(options = {}) ⇒ Engine
constructor
Create an
Engine
for running processes. -
#kill_children(signal = "SIGTERM") ⇒ Object
Send a signal to all processes started by this
Engine
. -
#killall(signal = "SIGTERM") ⇒ Object
Send a signal to the whole process group.
-
#load_env(filename) ⇒ Object
Load a .env file into the
env
for thisEngine
. -
#load_procfile(filename) ⇒ Object
Register processes by reading a Procfile.
-
#notice_signal ⇒ Object
Wake the main thread up via the selfpipe when there’s a signal.
-
#port_for(process, instance, base = nil) ⇒ Object
Get the port for a given process and offset.
-
#process(name) ⇒ Object
Get the
Process
for a specifid name. -
#process_names ⇒ Object
List the available process names.
-
#register(name, command, options = {}) ⇒ Object
Register a process to be run by this
Engine
. -
#register_signal_handlers ⇒ Object
Set up deferred signal handlers.
-
#restore_default_signal_handlers ⇒ Object
Unregister deferred signal handlers.
-
#root ⇒ Object
Get the root directory for this
Engine
. -
#start ⇒ Object
Start the processes registered to this
Engine
.
Constructor Details
#initialize(options = {}) ⇒ Engine
Create an Engine
for running processes
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/foreman/engine.rb', line 27 def initialize(={}) @options = .dup @options[:formation] ||= "all=1" @options[:timeout] ||= 5 @env = {} @mutex = Mutex.new @names = {} @processes = [] @running = {} @readers = {} @shutdown = false # Self-pipe for deferred signal-handling (ala djb: http://cr.yp.to/docs/selfpipe.html) reader, writer = create_pipe reader.close_on_exec = true if reader.respond_to?(:close_on_exec) writer.close_on_exec = true if writer.respond_to?(:close_on_exec) @selfpipe = { :reader => reader, :writer => writer } # Set up a global signal queue # http://blog.rubybestpractices.com/posts/ewong/016-Implementing-Signal-Handlers.html Thread.main[:signal_queue] = [] end |
Instance Attribute Details
#env ⇒ Object (readonly)
Returns the value of attribute env.
15 16 17 |
# File 'lib/foreman/engine.rb', line 15 def env @env end |
#options ⇒ Object (readonly)
Returns the value of attribute options.
16 17 18 |
# File 'lib/foreman/engine.rb', line 16 def @options end |
#processes ⇒ Object (readonly)
Returns the value of attribute processes.
17 18 19 |
# File 'lib/foreman/engine.rb', line 17 def processes @processes end |
Instance Method Details
#base_port ⇒ Object
Get the base port for this foreman instance
275 276 277 |
# File 'lib/foreman/engine.rb', line 275 def base_port ([:port] || env["PORT"] || ENV["PORT"] || 5000).to_i end |
#clear ⇒ Object
Clear the processes registered to this Engine
151 152 153 154 |
# File 'lib/foreman/engine.rb', line 151 def clear @names = {} @processes = [] end |
#each_process ⇒ Object
Yield each Process
in order
242 243 244 245 246 |
# File 'lib/foreman/engine.rb', line 242 def each_process process_names.each do |name| yield name, process(name) end end |
#environment ⇒ Object
deprecated
280 281 282 |
# File 'lib/foreman/engine.rb', line 280 def environment env end |
#formation ⇒ Object
Get the process formation
218 219 220 |
# File 'lib/foreman/engine.rb', line 218 def formation @formation ||= parse_formation([:formation]) end |
#handle_hangup ⇒ Object
Handle a HUP signal
128 129 130 131 |
# File 'lib/foreman/engine.rb', line 128 def handle_hangup system "SIGHUP received, starting shutdown" @shutdown = true end |
#handle_interrupt ⇒ Object
Handle an INT signal
121 122 123 124 |
# File 'lib/foreman/engine.rb', line 121 def handle_interrupt system "SIGINT received, starting shutdown" @shutdown = true end |
#handle_signal(sig) ⇒ Object
Invoke the real handler for signal sig
. This shouldn’t be called directly by signal handlers, as it might invoke code which isn’t re-entrant.
99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/foreman/engine.rb', line 99 def handle_signal(sig) case sig when :TERM handle_term_signal when :INT handle_interrupt when :HUP handle_hangup else system "unhandled signal #{sig}" end end |
#handle_term_signal ⇒ Object
Handle a TERM signal
114 115 116 117 |
# File 'lib/foreman/engine.rb', line 114 def handle_term_signal system "SIGTERM received, starting shutdown" @shutdown = true end |
#kill_children(signal = "SIGTERM") ⇒ Object
Send a signal to all processes started by this Engine
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
# File 'lib/foreman/engine.rb', line 182 def kill_children(signal="SIGTERM") if Foreman.windows? @running.each do |pid, (process, index)| system "sending #{signal} to #{name_for(pid)} at pid #{pid}" begin Process.kill(signal, pid) rescue Errno::ESRCH, Errno::EPERM end end else begin Process.kill signal, *@running.keys unless @running.empty? rescue Errno::ESRCH, Errno::EPERM end end end |
#killall(signal = "SIGTERM") ⇒ Object
Send a signal to the whole process group.
203 204 205 206 207 208 209 210 211 212 |
# File 'lib/foreman/engine.rb', line 203 def killall(signal="SIGTERM") if Foreman.windows? kill_children(signal) else begin Process.kill "-#{signal}", Process.pid rescue Errno::ESRCH, Errno::EPERM end end end |
#load_env(filename) ⇒ Object
Load a .env file into the env
for this Engine
172 173 174 175 176 |
# File 'lib/foreman/engine.rb', line 172 def load_env(filename) Foreman::Env.new(filename).entries do |name, value| @env[name] = value end end |
#load_procfile(filename) ⇒ Object
Register processes by reading a Procfile
160 161 162 163 164 165 166 |
# File 'lib/foreman/engine.rb', line 160 def load_procfile(filename) [:root] ||= File.dirname(filename) Foreman::Procfile.new(filename).entries do |name, command| register name, command, :cwd => [:root] end self end |
#notice_signal ⇒ Object
Wake the main thread up via the selfpipe when there’s a signal
85 86 87 88 89 90 91 92 |
# File 'lib/foreman/engine.rb', line 85 def notice_signal @selfpipe[:writer].write_nonblock( '.' ) rescue Errno::EAGAIN # Ignore writes that would block rescue Errno::EINTR # Retry if another signal arrived while writing retry end |
#port_for(process, instance, base = nil) ⇒ Object
Get the port for a given process and offset
263 264 265 266 267 268 269 |
# File 'lib/foreman/engine.rb', line 263 def port_for(process, instance, base=nil) if base base + (@processes.index(process.process) * 100) + (instance - 1) else base_port + (@processes.index(process) * 100) + (instance - 1) end end |
#process(name) ⇒ Object
Get the Process
for a specifid name
236 237 238 |
# File 'lib/foreman/engine.rb', line 236 def process(name) @names.invert[name] end |
#process_names ⇒ Object
List the available process names
226 227 228 |
# File 'lib/foreman/engine.rb', line 226 def process_names @processes.map { |p| @names[p] } end |
#register(name, command, options = {}) ⇒ Object
Register a process to be run by this Engine
141 142 143 144 145 146 147 |
# File 'lib/foreman/engine.rb', line 141 def register(name, command, ={}) [:env] ||= env [:cwd] ||= File.dirname(command.split(" ").first) process = Foreman::Process.new(command, ) @names[process] = name @processes << process end |
#register_signal_handlers ⇒ Object
Set up deferred signal handlers
67 68 69 70 71 72 73 |
# File 'lib/foreman/engine.rb', line 67 def register_signal_handlers HANDLED_SIGNALS.each do |sig| if ::Signal.list.include? sig.to_s trap(sig) { Thread.main[:signal_queue] << sig ; notice_signal } end end end |
#restore_default_signal_handlers ⇒ Object
Unregister deferred signal handlers
77 78 79 80 81 |
# File 'lib/foreman/engine.rb', line 77 def restore_default_signal_handlers HANDLED_SIGNALS.each do |sig| trap(sig, :DEFAULT) if ::Signal.list.include? sig.to_s end end |
#root ⇒ Object
Get the root directory for this Engine
252 253 254 |
# File 'lib/foreman/engine.rb', line 252 def root File.([:root] || Dir.pwd) end |
#start ⇒ Object
Start the processes registered to this Engine
54 55 56 57 58 59 60 61 62 63 |
# File 'lib/foreman/engine.rb', line 54 def start register_signal_handlers startup spawn_processes watch_for_output sleep 0.1 wait_for_shutdown_or_child_termination shutdown exit(@exitstatus) if @exitstatus end |