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