Parent

Class Index [+]

Quicksearch

Merb::Rack::AbstractAdapter

Public Class Methods

exit_process(status = 0) click to toggle source

Exit the process with the specified status.

Parameters

status

The exit code of the process.

:api: private

     # File lib/merb-core/rack/adapter/abstract.rb, line 314
314:       def self.exit_process(status = 0)
315:         exit(status)
316:       end
new_server(port) click to toggle source

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.

Parameters

port

The port the server should listen on

:api: plugin @overridable

    # File lib/merb-core/rack/adapter/abstract.rb, line 68
68:       def self.new_server(port)
69:         raise NotImplemented
70:       end
process_title(whoami, port) click to toggle source

Set the process title.

Parameters

whoami

Either :spawner for the master process or :worker for any of the worker

  processes. 
port

The base port that the app is running on.

:api: private

     # File lib/merb-core/rack/adapter/abstract.rb, line 326
326:       def self.process_title(whoami, port)
327:         name = Merb::Config[:name]
328:         app  = "merb#{" : #{name}" if (name && name != "merb")}"
329:         max_port  = Merb::Config[:cluster] ? (Merb::Config[:cluster] - 1) : 0
330:         numbers   = ((whoami != :worker) && (max_port > 0)) ? "#{port}..#{port + max_port}" : port
331:         file      = Merb::Config[:socket_file] % port if Merb::Config[:socket_file]
332:         
333:         listening_on = if Merb::Config[:socket]
334:           "socket#{'s' if max_port > 0 && whoami != :worker} #{numbers} "           "#{file ? file : "#{Merb.log_path}/#{name}.#{port}.sock"}"
335:         else
336:           "port#{'s' if max_port > 0 && whoami != :worker} #{port}"
337:         end
338:         "#{app} : #{whoami} (#{listening_on})"
339:       end
spawn_worker(port) click to toggle source

Spawn a new worker process at a port.

Parameters

port

The port to start the worker process on.

:api: private

     # File lib/merb-core/rack/adapter/abstract.rb, line 93
 93:       def self.spawn_worker(port)
 94:         worker_pid = Kernel.fork
 95: 
 96:         # If we have a worker_pid, we're in the parent.
 97:         if worker_pid.nil?
 98:           # Seed the random number generator
 99:           Kernel.srand
100: 
101:           # Restart the run_later worker, unless we're in the parent or it's alive.
102:           Merb::Worker.restart unless Merb::Worker.alive?
103: 
104:           # Spawn the worker
105:           start_at_port(port, @opts)
106: 
107:           throw(:new_worker)
108:         end
109: 
110:         @pids[port] = worker_pid
111:         $WORKERS = @pids.values
112:       end
start(opts={}) click to toggle source

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.

Parameters

opts

A hash of options

  socket: the socket to bind to
  port: the port to bind to
  cluster: the number 

:api: private

     # File lib/merb-core/rack/adapter/abstract.rb, line 126
126:       def self.start(opts={})
127:         @opts = opts
128:         $WORKERS ||= []
129:         parent = nil
130: 
131:         @pids = {}
132:         port = (opts[:socket] || opts[:port]).to_i
133:         max_port = Merb::Config[:cluster] ? Merb::Config[:cluster] - 1 : 0
134: 
135:         # If we only have a single merb, just start it up and dispense with
136:         # the spawner/worker setup.
137:         if max_port == 0
138:           start_at_port(port)
139:           return
140:         end
141: 
142:         $0 = process_title(:spawner, port)
143: 
144:         # For each port, spawn a new worker. The parent will continue in
145:         # the loop, while the worker will throw :new_worker and be booted
146:         # out of the loop.
147:         catch(:new_worker) do
148:           0.upto(max_port) do |i|
149:             parent = spawn_worker(port + i)
150:           end
151:         end
152: 
153:         # If we're in a worker, we're done. Otherwise, we've completed
154:         # setting up workers and now need to watch them.
155:         return unless parent
156: 
157:         # For each worker, set up a thread in the spawner to watch it
158:         0.upto(max_port) do |i|
159:           Thread.new do
160:             catch(:new_worker) do
161:               loop do
162:                 pid, status = @pids[port + i], nil
163:                 poller = Merb::System::PortablePoller.new(pid)
164:                 begin
165:                   i = 0
166:                   loop do                    
167:                     # Watch for the pid to exit.
168:                     _, status = Process.wait2(pid, Process::WNOHANG)
169:                     break if status
170:                     
171:                     if (i % 120 == 0) && Merb::Config[:max_memory] && poller.memory > Merb::Config[:max_memory]
172:                       Process.kill("INT", pid)
173:                       if (Process.kill(0, pid) rescue false)
174:                         sleep Merb::Config[:hang_time] || 5
175:                         Process.kill(9, pid)
176:                         Process.wait2(pid) if (Process.kill(0, pid) rescue false)
177:                       end
178:                       
179:                       status = Struct.new(:exitstatus).new(nil)
180:                       break
181:                     end
182:                     i += 1
183:                     sleep 0.25
184:                   end
185: 
186:                   # If the pid doesn't exist, we want to silently exit instead of
187:                   # raising here.
188:                 rescue SystemCallError => e
189:                 ensure
190:                   # If there was no worker with that PID, the status was non-0
191:                   # (we send back a status of 128 when ABRT is called on a 
192:                   # worker, and Merb.fatal! exits with a status of 1), or if
193:                   # Merb is in the process of exiting, *then* don't respawn.
194:                   # Note that processes killed with kill -9 will return no
195:                   # exitstatus, and we respawn them.
196:                   if !status || 
197:                     (status.exitstatus && status.exitstatus != 0) || 
198:                     Merb.exiting then
199:                     Thread.exit
200:                   end
201:                 end
202: 
203:                 # Otherwise, respawn the worker, and watch it again.
204:                 spawn_worker(port + i)
205:               end
206:             end
207:           end
208:         end
209: 
210:         # The spawner process will make it here, and when it does, it should just 
211:         # sleep so it can pick up ctrl-c if it's in console mode.
212:         sleep
213: 
214:       end
start_at_port(port, opts = @opts) click to toggle source

Fork a server on the specified port and start the app.

Parameters

port

The port to start the server on

opts

The hash of options, defaults to the @opts

  instance variable.  

:api: private

     # File lib/merb-core/rack/adapter/abstract.rb, line 224
224:       def self.start_at_port(port, opts = @opts)
225:         at_exit do
226:           Merb::Server.remove_pid(port)
227:         end
228: 
229:         # If Merb is daemonized, trap INT. If it's not daemonized,
230:         # we let the master process' ctrl-c control the cluster
231:         # of workers.
232:         if Merb::Config[:daemonize]
233:           Merb.trap('INT') do
234:             Merb.exiting = true
235:             stop
236:             Merb.logger.warn! "Exiting port #{port}\n"
237:             exit_process
238:           end
239:           # If it was not fork_for_class_load, we already set up
240:           # ctrl-c handlers in the master thread.
241:         elsif Merb::Config[:fork_for_class_load]
242:           if Merb::Config[:console_trap]
243:             Merb::Server.add_irb_trap
244:           end
245:         end
246: 
247:         # In daemonized mode or not, support HUPing the process to
248:         # restart it.
249:         Merb.trap('HUP') do
250:           Merb.exiting = true
251:           stop
252:           Merb.logger.warn! "Exiting port #{port} on #{Process.pid}\n"
253:           exit_process
254:         end
255: 
256:         # ABRTing the process will kill it, and it will not be respawned.
257:         Merb.trap('ABRT') do
258:           Merb.exiting = true
259:           stopped = stop(128)
260:           Merb.logger.warn! "Exiting port #{port}\n" if stopped
261:           exit_process(128)
262:         end
263: 
264:         # Each worker gets its own `ps' name.
265:         $0 = process_title(:worker, port)
266: 
267:         # Store the PID for this worker
268:         Merb::Server.store_pid(port)
269: 
270:         Merb::Config[:log_delimiter] = "#{process_title(:worker, port)} ~ "
271: 
272:         Merb.reset_logger!
273:         Merb.logger.warn!("Starting #{self.name.split("::").last} at port #{port}")
274: 
275:         # If we can't connect to the port, keep trying until we can. Print
276:         # a warning about this once. Try every 0.25s.
277:         printed_warning = false
278:         loop do
279:           begin
280:             # Call the adapter's new_server method, which should attempt
281:             # to bind to a port.
282:             new_server(port)
283:           rescue Errno::EADDRINUSE => e
284:             if Merb::Config[:bind_fail_fatal]
285:               Merb.fatal! "Could not bind to #{port}. It was already in use", e
286:             end
287:             
288:             unless printed_warning
289:               Merb.logger.warn! "Port #{port} is in use, "                  "Waiting for it to become available."
290:               printed_warning = true
291:             end
292: 
293:             sleep 0.25
294:             next
295:           end
296:           break
297:         end
298: 
299:         Merb.logger.warn! "Successfully bound to port #{port}"
300: 
301:         Merb::Server.change_privilege
302: 
303:         # Call the adapter's start_server method.
304:         start_server
305:       end
start_server() click to toggle source

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 lib/merb-core/rack/adapter/abstract.rb, line 54
54:       def self.start_server
55:         raise NotImplemented
56:       end
stop(status) click to toggle source

This method is designed to be overridden in a rack adapter. It will be called to stop the adapter server.

Parameters

status

The exit status the adapter should exit with.

Returns

Boolean

True if the server was properly stopped.

:api: plugin @overridable

    # File lib/merb-core/rack/adapter/abstract.rb, line 83
83:       def self.stop(status)
84:         raise NotImplemented
85:       end

Disabled; run with --debug to generate this.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.