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
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 28 def initialize(={}) @options = .dup @options[:formation] ||= ([:concurrency] || "all=1") @options[:timeout] ||= 5 @env = {} @mutex = Mutex.new @names = {} @processes = [] @running = {} @readers = {} # 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.
16 17 18 |
# File 'lib/foreman/engine.rb', line 16 def env @env end |
#options ⇒ Object (readonly)
Returns the value of attribute options.
17 18 19 |
# File 'lib/foreman/engine.rb', line 17 def @options end |
#processes ⇒ Object (readonly)
Returns the value of attribute processes.
18 19 20 |
# File 'lib/foreman/engine.rb', line 18 def processes @processes end |
Instance Method Details
#base_port ⇒ Object
Get the base port for this foreman instance
274 275 276 |
# File 'lib/foreman/engine.rb', line 274 def base_port ([:port] || env["PORT"] || ENV["PORT"] || 5000).to_i end |
#clear ⇒ Object
Clear the processes registered to this Engine
150 151 152 153 |
# File 'lib/foreman/engine.rb', line 150 def clear @names = {} @processes = [] end |
#each_process ⇒ Object
Yield each Process
in order
241 242 243 244 245 |
# File 'lib/foreman/engine.rb', line 241 def each_process process_names.each do |name| yield name, process(name) end end |
#environment ⇒ Object
deprecated
279 280 281 |
# File 'lib/foreman/engine.rb', line 279 def environment env end |
#formation ⇒ Object
Get the process formation
217 218 219 |
# File 'lib/foreman/engine.rb', line 217 def formation @formation ||= parse_formation([:formation]) end |
#handle_hangup ⇒ Object
Handle a HUP signal
127 128 129 130 |
# File 'lib/foreman/engine.rb', line 127 def handle_hangup puts "SIGHUP received" terminate_gracefully end |
#handle_interrupt ⇒ Object
Handle an INT signal
120 121 122 123 |
# File 'lib/foreman/engine.rb', line 120 def handle_interrupt puts "SIGINT received" terminate_gracefully 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.
98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/foreman/engine.rb', line 98 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
113 114 115 116 |
# File 'lib/foreman/engine.rb', line 113 def handle_term_signal puts "SIGTERM received" terminate_gracefully end |
#kill_children(signal = "SIGTERM") ⇒ Object
Send a signal to all processes started by this Engine
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
# File 'lib/foreman/engine.rb', line 181 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.
202 203 204 205 206 207 208 209 210 211 |
# File 'lib/foreman/engine.rb', line 202 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
171 172 173 174 175 |
# File 'lib/foreman/engine.rb', line 171 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
159 160 161 162 163 164 165 |
# File 'lib/foreman/engine.rb', line 159 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
84 85 86 87 88 89 90 91 |
# File 'lib/foreman/engine.rb', line 84 def notice_signal @selfpipe[:writer].write_nonblock( '.' ) rescue Errno::EAGAIN # Ignore writes that would block rescue Errno::EINT # 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
262 263 264 265 266 267 268 |
# File 'lib/foreman/engine.rb', line 262 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
235 236 237 |
# File 'lib/foreman/engine.rb', line 235 def process(name) @names.invert[name] end |
#process_names ⇒ Object
List the available process names
225 226 227 |
# File 'lib/foreman/engine.rb', line 225 def process_names @processes.map { |p| @names[p] } end |
#register(name, command, options = {}) ⇒ Object
Register a process to be run by this Engine
140 141 142 143 144 145 146 |
# File 'lib/foreman/engine.rb', line 140 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
66 67 68 69 70 71 72 |
# File 'lib/foreman/engine.rb', line 66 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
76 77 78 79 80 |
# File 'lib/foreman/engine.rb', line 76 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
251 252 253 |
# File 'lib/foreman/engine.rb', line 251 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 |
# File 'lib/foreman/engine.rb', line 54 def start register_signal_handlers startup spawn_processes watch_for_output sleep 0.1 watch_for_termination { terminate_gracefully } shutdown end |