| Class | Merb::Rack::AbstractAdapter |
| In: |
merb-core/lib/merb-core/rack/adapter/abstract.rb
|
| Parent: | Object |
Exit the process with the specified status.
| status<Integer>: | The exit code of the process. |
:api: private
# File merb-core/lib/merb-core/rack/adapter/abstract.rb, line 307
307: def self.exit_process(status = 0)
308: exit(status)
309: end
This method is designed to be overridden in a rack adapter. It will be called to create a new instance of the server for the adapter to start. The adapter should attempt to bind to a port at this point. This is called from the AbstractAdapter start method.
| port<Integer>: | The port the server should listen on |
:api: plugin @overridable
# File merb-core/lib/merb-core/rack/adapter/abstract.rb, line 68
68: def self.new_server(port)
69: raise NotImplemented
70: end
Set the process title.
| whoami<Symbol>: | Either :spawner for the master process or :worker for any of the worker |
processes.
| port<Integer>: | The base port that the app is running on. |
:api: private
# File merb-core/lib/merb-core/rack/adapter/abstract.rb, line 319
319: def self.process_title(whoami, port)
320: name = Merb::Config[:name]
321: app = "merb#{" : #{name}" if (name && name != "merb")}"
322: max_port = Merb::Config[:cluster] ? (Merb::Config[:cluster] - 1) : 0
323: numbers = ((whoami != :worker) && (max_port > 0)) ? "#{port}..#{port + max_port}" : port
324: file = Merb::Config[:socket_file] % port if Merb::Config[:socket_file]
325:
326: listening_on = if Merb::Config[:socket]
327: "socket#{'s' if max_port > 0 && whoami != :worker} #{numbers} "\
328: "#{file ? file : "#{Merb.log_path}/#{name}.#{port}.sock"}"
329: else
330: "port#{'s' if max_port > 0 && whoami != :worker} #{port}"
331: end
332: "#{app} : #{whoami} (#{listening_on})"
333: end
Spawn a new worker process at a port.
| port<Integer>: | The port to start the worker process on. |
:api: private
# File merb-core/lib/merb-core/rack/adapter/abstract.rb, line 93
93: def self.spawn_worker(port)
94: worker_pid = Kernel.fork
95: start_at_port(port, @opts) unless worker_pid
96:
97: # If we have a worker_pid, we're in the parent.
98: throw(:new_worker) unless worker_pid
99:
100: @pids[port] = worker_pid
101: $WORKERS = @pids.values
102: end
The main start method for bootloaders that support forking. This method launches the adapters which inherit using the new_server and start_server methods. This method should not be overridden in adapters which want to fork.
| opts<Hash>: | A hash of options |
socket: the socket to bind to port: the port to bind to cluster: the number
:api: private
# File merb-core/lib/merb-core/rack/adapter/abstract.rb, line 116
116: def self.start(opts={})
117: @opts = opts
118: $WORKERS ||= []
119: parent = nil
120:
121: @pids = {}
122: port = (opts[:socket] || opts[:port]).to_i
123: max_port = Merb::Config[:cluster] ? Merb::Config[:cluster] - 1 : 0
124:
125: # If we only have a single merb, just start it up and dispense with
126: # the spawner/worker setup.
127: if max_port == 0
128: start_at_port(port)
129: return
130: end
131:
132: $0 = process_title(:spawner, port)
133:
134: # For each port, spawn a new worker. The parent will continue in
135: # the loop, while the worker will throw :new_worker and be booted
136: # out of the loop.
137: catch(:new_worker) do
138: 0.upto(max_port) do |i|
139: parent = spawn_worker(port + i)
140: end
141: end
142:
143: # If we're in a worker, we're done. Otherwise, we've completed
144: # setting up workers and now need to watch them.
145: return unless parent
146:
147: # For each worker, set up a thread in the spawner to watch it
148: 0.upto(max_port) do |i|
149: Thread.new do
150: catch(:new_worker) do
151: loop do
152: pid, status = @pids[port + i], nil
153: poller = Merb::System::PortablePoller.new(pid)
154: begin
155: tick = 1
156: loop do
157: # Watch for the pid to exit.
158: _, status = Process.wait2(pid, Process::WNOHANG)
159: break if status
160:
161: if (tick % 120 == 0) && Merb::Config[:max_memory] && poller.memory > Merb::Config[:max_memory]
162: tick = 1
163: Process.kill("INT", pid)
164: if (Process.kill(0, pid) rescue false)
165: sleep Merb::Config[:hang_time] || 5
166: Process.kill(9, pid)
167: Process.wait2(pid) if (Process.kill(0, pid) rescue false)
168: end
169:
170: status = Struct.new(:exitstatus).new(nil)
171: break
172: end
173: tick += 1
174: sleep 0.25
175: end
176:
177: # If the pid doesn't exist, we want to silently exit instead of
178: # raising here.
179: rescue SystemCallError => e
180: ensure
181: # If there was no worker with that PID, the status was non-0
182: # (we send back a status of 128 when ABRT is called on a
183: # worker, and Merb.fatal! exits with a status of 1), or if
184: # Merb is in the process of exiting, *then* don't respawn.
185: # Note that processes killed with kill -9 will return no
186: # exitstatus, and we respawn them.
187: if !status ||
188: (status.exitstatus && status.exitstatus != 0) ||
189: Merb.exiting then
190: Thread.exit
191: end
192: end
193:
194: # Otherwise, respawn the worker, and watch it again.
195: spawn_worker(port + i)
196: end
197: end
198: end
199: end
200:
201: # The spawner process will make it here, and when it does, it should just
202: # sleep so it can pick up ctrl-c if it's in console mode.
203: sleep
204:
205: end
Fork a server on the specified port and start the app.
| port<Integer>: | The port to start the server on |
| opts<Hash>: | The hash of options, defaults to the @opts |
instance variable.
:api: private
# File merb-core/lib/merb-core/rack/adapter/abstract.rb, line 215
215: def self.start_at_port(port, opts = @opts)
216: at_exit do
217: Merb::Server.remove_pid(port)
218: end
219:
220: Merb::Worker.start unless Merb.testing?
221:
222: # If Merb is daemonized, trap INT. If it's not daemonized,
223: # we let the master process' ctrl-c control the cluster
224: # of workers.
225: if Merb::Config[:daemonize]
226: Merb.trap('INT') do
227: Merb.exiting = true
228: stop
229: Merb.logger.warn! "Exiting port #{port}\n"
230: exit_process
231: end
232: # If it was not fork_for_class_load, we already set up
233: # ctrl-c handlers in the master thread.
234: elsif Merb::Config[:fork_for_class_load]
235: if Merb::Config[:console_trap]
236: Merb::Server.add_irb_trap
237: end
238: end
239:
240: # In daemonized mode or not, support HUPing the process to
241: # restart it.
242: Merb.trap('HUP') do
243: Merb.exiting = true
244: stop
245: Merb.logger.warn! "Exiting port #{port} on #{Process.pid}\n"
246: exit_process
247: end
248:
249: # ABRTing the process will kill it, and it will not be respawned.
250: Merb.trap('ABRT') do
251: Merb.exiting = true
252: stopped = stop(128)
253: Merb.logger.warn! "Exiting port #{port}\n" if stopped
254: exit_process(128)
255: end
256:
257: # Each worker gets its own `ps' name.
258: $0 = process_title(:worker, port)
259:
260: # Store the PID for this worker
261: Merb::Server.store_pid(port)
262:
263: Merb::Config[:log_delimiter] = "#{process_title(:worker, port)} ~ "
264:
265: Merb.reset_logger!
266: Merb.logger.warn!("Starting #{self.name.split("::").last} at port #{port}")
267:
268: # If we can't connect to the port, keep trying until we can. Print
269: # a warning about this once. Try every 0.25s.
270: printed_warning = false
271: loop do
272: begin
273: # Call the adapter's new_server method, which should attempt
274: # to bind to a port.
275: new_server(port)
276: rescue Errno::EADDRINUSE => e
277: if Merb::Config[:bind_fail_fatal]
278: Merb.fatal! "Could not bind to #{port}. It was already in use", e
279: end
280:
281: unless printed_warning
282: Merb.logger.warn! "Port #{port} is in use, " \
283: "Waiting for it to become available."
284: printed_warning = true
285: end
286:
287: sleep 0.25
288: next
289: end
290: break
291: end
292:
293: Merb.logger.warn! "Successfully bound to port #{port}"
294:
295: Merb::Server.change_privilege
296:
297: # Call the adapter's start_server method.
298: start_server
299: end
This method is designed to be overridden in a rack adapter. It will be called to start a server created with the new_server method. This is called from the AbstractAdapter start method.
:api: plugin @overridable
# File merb-core/lib/merb-core/rack/adapter/abstract.rb, line 54
54: def self.start_server
55: raise NotImplemented
56: end
This method is designed to be overridden in a rack adapter. It will be called to stop the adapter server.
| status<Integer>: | The exit status the adapter should exit with. |
| Boolean: | True if the server was properly stopped. |
:api: plugin @overridable
# File merb-core/lib/merb-core/rack/adapter/abstract.rb, line 83
83: def self.stop(status)
84: raise NotImplemented
85: end