Class | Merb::Server |
In: |
merb-core/lib/merb-core/server.rb
|
Parent: | Object |
Change privileges of the process to the specified user and group.
user<String>: | The user to change the process to. |
group<String>: | The group to change the process to. |
If group is left out, the user will be used as the group.
:api: private
# File merb-core/lib/merb-core/server.rb, line 324 324: def _change_privilege(user, group=user) 325: Merb.logger.warn! "Changing privileges to #{user}:#{group}" 326: 327: uid, gid = Process.euid, Process.egid 328: 329: begin 330: target_uid = Etc.getpwnam(user).uid 331: rescue ArgumentError => e 332: Merb.fatal!("Failed to change to user #{user}, does the user exist?", e) 333: return false 334: end 335: 336: begin 337: target_gid = Etc.getgrnam(group).gid 338: rescue ArgumentError => e 339: Merb.fatal!("Failed to change to group #{group}, does the group exist?", e) 340: return false 341: end 342: 343: if (uid != target_uid) || (gid != target_gid) 344: # Change process ownership 345: Process.initgroups(user, target_gid) 346: Process::GID.change_privilege(target_gid) 347: Process::UID.change_privilege(target_uid) 348: end 349: true 350: rescue Errno::EPERM => e 351: Merb.fatal! "Permission denied for changing user:group to #{user}:#{group}.", e 352: false 353: end
Add trap to enter IRB on SIGINT. Process exit if second SIGINT is received.
:api: private
# File merb-core/lib/merb-core/server.rb, line 358 358: def add_irb_trap 359: Merb.trap("INT") do 360: if @interrupted 361: Merb.logger.warn! "Interrupt received a second time, exiting!\n" 362: exit 363: end 364: 365: @interrupted = true 366: Merb.logger.warn! "Interrupt a second time to quit." 367: Kernel.sleep 1.5 368: ARGV.clear # Avoid passing args to IRB 369: 370: if @irb.nil? 371: require "irb" 372: IRB.setup(nil) 373: @irb = IRB::Irb.new(nil) 374: IRB.conf[:MAIN_CONTEXT] = @irb.context 375: end 376: 377: Merb.trap(:INT) { @irb.signal_handle } 378: catch(:IRB_EXIT) { @irb.eval_input } 379: 380: Merb.logger.warn! "Exiting from IRB mode back into server mode." 381: @interrupted = false 382: add_irb_trap 383: end 384: end
port<~to_s>: | The port to check for Merb instances on. |
Boolean: | True if Merb is running on the specified port. |
:api: private
# File merb-core/lib/merb-core/server.rb, line 54 54: def alive?(port) 55: pidfile = pid_file(port) 56: pid = pid_in_file(pidfile) 57: Process.kill(0, pid) 58: true 59: rescue Errno::ESRCH, Errno::ENOENT 60: false 61: rescue Errno::EACCES => e 62: Merb.fatal!("You don't have access to the PID file at #{pidfile}: #{e.message}") 63: end
Starts up Merb by running the bootloader and starting the adapter.
:api: private
# File merb-core/lib/merb-core/server.rb, line 168 168: def bootup 169: Merb.trap("TERM") { shutdown } 170: 171: Merb.logger.warn! "Running bootloaders..." if Merb::Config[:verbose] 172: BootLoader.run 173: Merb.logger.warn! "Starting Rack adapter..." if Merb::Config[:verbose] 174: Merb.adapter.start(Merb::Config.to_hash) 175: end
Change process user/group to those specified in Merb::Config.
:api: private
# File merb-core/lib/merb-core/server.rb, line 190 190: def change_privilege 191: if Merb::Config[:user] && Merb::Config[:group] 192: Merb.logger.verbose! "About to change privilege to group " \ 193: "#{Merb::Config[:group]} and user #{Merb::Config[:user]}" 194: _change_privilege(Merb::Config[:user], Merb::Config[:group]) 195: elsif Merb::Config[:user] 196: Merb.logger.verbose! "About to change privilege to user " \ 197: "#{Merb::Config[:user]}" 198: _change_privilege(Merb::Config[:user]) 199: else 200: return true 201: end 202: end
port<~to_s>: | The port of the Merb process to daemonize. |
:api: private
# File merb-core/lib/merb-core/server.rb, line 141 141: def daemonize(port) 142: Merb.logger.warn! "About to fork..." if Merb::Config[:verbose] 143: fork do 144: Process.setsid 145: exit if fork 146: Merb.logger.warn! "In #{Process.pid}" if Merb.logger 147: File.umask 0000 148: STDIN.reopen "/dev/null" 149: STDOUT.reopen "/dev/null", "a" 150: STDERR.reopen STDOUT 151: begin 152: Dir.chdir Merb::Config[:merb_root] 153: rescue Errno::EACCES => e 154: Merb.fatal! "You specified Merb root as #{Merb::Config[:merb_root]}, " \ 155: "yet the current user does not have access to it. ", e 156: end 157: at_exit { remove_pid_file(port) } 158: Merb::Config[:port] = port 159: bootup 160: end 161: rescue NotImplementedError => e 162: Merb.fatal! "Daemonized mode is not supported on your platform. ", e 163: end
port<~to_s>: | The port of the Merb process to kill. |
sig<~to_s>: | The signal to send to the process, the default is 9 - SIGKILL. |
No Name Default Action Description 1 SIGHUP terminate process terminal line hangup 2 SIGINT terminate process interrupt program 3 SIGQUIT create core image quit program 4 SIGILL create core image illegal instruction 9 SIGKILL terminate process kill program 15 SIGTERM terminate process software termination signal 30 SIGUSR1 terminate process User defined signal 1 31 SIGUSR2 terminate process User defined signal 2
If you pass "all" as the port, the signal will be sent to all Merb processes.
:api: private
# File merb-core/lib/merb-core/server.rb, line 88 88: def kill(port, sig = "INT") 89: if sig.is_a?(Integer) 90: sig = Signal.list.invert[sig] 91: end 92: 93: Merb::BootLoader::BuildFramework.run 94: 95: # If we kill the master, then the workers should be reaped also. 96: if %w(main master all).include?(port) 97: # If a graceful exit is requested then send INT to the master process. 98: # 99: # Otherwise read pids from pid files and try to kill each process in turn. 100: kill_pid(sig, pid_file("main")) if sig == "INT" 101: else 102: kill_pid(sig, pid_file(port)) 103: end 104: end
Sends the provided signal to the process pointed at by the provided pid file. :api: private
# File merb-core/lib/merb-core/server.rb, line 108 108: def kill_pid(sig, file) 109: begin 110: pid = pid_in_file(file) 111: Merb.logger.fatal! "Killing pid #{pid} with #{sig}" 112: Process.kill(sig, pid) 113: FileUtils.rm(file) if File.exist?(file) 114: rescue Errno::EINVAL 115: Merb.logger.fatal! "Failed to kill PID #{pid} with #{sig}: '#{sig}' is an invalid " \ 116: "or unsupported signal number." 117: rescue Errno::EPERM 118: Merb.logger.fatal! "Failed to kill PID #{pid} with #{sig}: Insufficient permissions." 119: rescue Errno::ESRCH 120: FileUtils.rm file 121: Merb.logger.fatal! "Failed to kill PID #{pid} with #{sig}: Process is " \ 122: "deceased or zombie." 123: rescue Errno::EACCES => e 124: Merb.logger.fatal! e.message 125: rescue Errno::ENOENT => e 126: # This should not cause abnormal exit, which is why 127: # we do not use Merb.fatal but instead just log with max level. 128: Merb.logger.fatal! "Could not find a PID file at #{file}. " \ 129: "Most likely the process is no longer running and the pid file was not cleaned up." 130: rescue Exception => e 131: if !e.is_a?(SystemExit) 132: Merb.logger.fatal! "Failed to kill PID #{pid.inspect} with #{sig.inspect}: #{e.message}" 133: end 134: end 135: end
Gets the pid file for the specified port/socket.
port<~to_s>: | The port/socket of the Merb process to whom the the PID file belongs to. |
String: | Location of pid file for specified port. If clustered and pid_file option is specified, it adds the port/socket value to the path. |
:api: private
# File merb-core/lib/merb-core/server.rb, line 290 290: def pid_file(port) 291: pidfile = Merb::Config[:pid_file] || (Merb.log_path / "merb.%s.pid") 292: pidfile % port 293: end
Get a list of the pid files.
Array: | List of pid file paths. If not running clustered, the array contains a single path. |
:api: private
# File merb-core/lib/merb-core/server.rb, line 302 302: def pid_files 303: if Merb::Config[:pid_file] 304: if Merb::Config[:cluster] 305: Dir[Merb::Config[:pid_file] % "*"] 306: else 307: [ Merb::Config[:pid_file] ] 308: end 309: else 310: Dir[Merb.log_path / "merb.*.pid"] 311: end 312: end
:api: private
# File merb-core/lib/merb-core/server.rb, line 66 66: def pid_in_file(pidfile) 67: File.read(pidfile).chomp.to_i 68: end
Delete the pidfile for the specified port/socket.
:api: private
# File merb-core/lib/merb-core/server.rb, line 245 245: def remove_pid(port) 246: FileUtils.rm(pid_file(port)) if File.file?(pid_file(port)) 247: end
Removes a PID file used by the server from the filesystem. This uses :pid_file options from configuration when provided or merb.<port/socket>.pid in log directory by default.
port<~to_s>: | The port of the Merb process to whom the the PID file belongs to. |
If Merb::Config[:pid_file] has been specified, that will be used instead of the port/socket based PID file.
:api: private
# File merb-core/lib/merb-core/server.rb, line 217 217: def remove_pid_file(port) 218: pidfile = pid_file(port) 219: if File.exist?(pidfile) 220: Merb.logger.warn! "Removing pid file #{pidfile} (port/socket: #{port})..." 221: FileUtils.rm(pidfile) 222: end 223: end
Shut down Merb, reap any workers if necessary.
:api: private
# File merb-core/lib/merb-core/server.rb, line 180 180: def shutdown(status = 0) 181: # reap_workers does exit but may not be called... 182: Merb::BootLoader::LoadClasses.reap_workers(status) if Merb::Config[:fork_for_class_load] 183: # which is why we exit explicitly here 184: exit(status) 185: end
Start a Merb server, in either foreground, daemonized or cluster mode.
port<~to_i>: | The port to which the first server instance should bind to. Subsequent server instances bind to the immediately following ports. |
cluster<~to_i>: | Number of servers to run in a cluster. |
If cluster is left out, then one process will be started. This process will be daemonized if Merb::Config[:daemonize] is true.
:api: private
# File merb-core/lib/merb-core/server.rb, line 23 23: def start(port, cluster=nil) 24: 25: @port = port 26: @cluster = cluster 27: 28: if Merb::Config[:daemonize] 29: pidfile = pid_file(port) 30: pid = File.read(pidfile).chomp.to_i if File.exist?(pidfile) 31: 32: unless alive?(@port) 33: remove_pid_file(@port) 34: Merb.logger.warn! "Daemonizing..." if Merb::Config[:verbose] 35: daemonize(@port) 36: else 37: Merb.fatal! "Merb is already running on port #{port}.\n" \ 38: "\e[0m \e[1;31;47mpid file: \e[34;47m#{pidfile}" \ 39: "\e[1;31;47m, process id is \e[34;47m#{pid}." 40: end 41: else 42: bootup 43: end 44: end
Stores a PID file on the filesystem. This uses :pid_file options from configuration when provided or merb.<port/socket>.pid in log directory by default.
port<~to_s>: | The port of the Merb process to whom the the PID file belongs to. |
If Merb::Config[:pid_file] has been specified, that will be used instead of the port/socket based PID file.
:api: private
# File merb-core/lib/merb-core/server.rb, line 262 262: def store_details(port = nil) 263: file = pid_file(port) 264: begin 265: FileUtils.mkdir_p(File.dirname(file)) 266: rescue Errno::EACCES => e 267: Merb.fatal! "Failed to store Merb logs in #{File.dirname(file)}, " \ 268: "permission denied. ", e 269: end 270: Merb.logger.warn! "Storing pid #{Process.pid} file to #{file}..." if Merb::Config[:verbose] 271: begin 272: File.open(file, 'w'){ |f| f.write(Process.pid.to_s) } 273: rescue Errno::EACCES => e 274: Merb.fatal! "Failed to access #{file}, permission denied.", e 275: end 276: end
Stores a PID file on the filesystem. This uses :pid_file options from configuration when provided or merb.<port>.pid in log directory by default.
port<~to_s>: | The port of the Merb process to whom the the PID file belongs to. |
If Merb::Config[:pid_file] has been specified, that will be used instead of the port/socket based PID file.
:api: private
# File merb-core/lib/merb-core/server.rb, line 238 238: def store_pid(port) 239: store_details(port) 240: end