### Home Classes Methods

### In Files

- lib/merb-core/server.rb

### Parent

Object

### Methods

- ::_change_privilege
- ::add_irb_trap
- ::alive?
- ::bootup
- ::change_privilege
- ::daemonize
- ::kill
- ::kill_pid
- ::pid_file
- ::pid_files
- ::pid_in_file
- ::remove_pid
- ::remove_pid_file
- ::shutdown
- ::start
- ::store_details
- ::store_pid

### Files

- CHANGELOG
- LICENSE
- README
- TODO

### Class/Module Index

Quicksearch

- Merb
- Merb::AbstractController
- Merb::AcceptType
- Merb::AuthenticationMixin
- Merb::AuthenticationMixin::BasicAuthentication
- Merb::BootLoader
- Merb::BootLoader::AfterAppLoads
- Merb::BootLoader::BackgroundServices
- Merb::BootLoader::BeforeAppLoads
- Merb::BootLoader::BuildFramework
- Merb::BootLoader::ChooseAdapter
- Merb::BootLoader::Cookies
- Merb::BootLoader::Defaults
- Merb::BootLoader::Dependencies
- Merb::BootLoader::DropPidFile
- Merb::BootLoader::LoadClasses
- Merb::BootLoader::Logger
- Merb::BootLoader::MimeTypes
- Merb::BootLoader::MixinSession
- Merb::BootLoader::RackUpApplication
- Merb::BootLoader::ReloadClasses
- Merb::BootLoader::ReloadClasses::TimedExecutor
- Merb::BootLoader::Router
- Merb::BootLoader::SetupSession
- Merb::BootLoader::SetupStubClasses
- Merb::BootLoader::Templates
- Merb::ConditionalGetMixin
- Merb::Config
- Merb::Config::ConfigBlock
- Merb::Const
- Merb::Controller
- Merb::ControllerExceptions
- Merb::ControllerExceptions::Accepted
- Merb::ControllerExceptions::ActionNotFound
- Merb::ControllerExceptions::BadGateway
- Merb::ControllerExceptions::BadRequest
- Merb::ControllerExceptions::Base
- Merb::ControllerExceptions::ClientError
- Merb::ControllerExceptions::Conflict
- Merb::ControllerExceptions::Continue
- Merb::ControllerExceptions::Created
- Merb::ControllerExceptions::ExpectationFailed
- Merb::ControllerExceptions::Forbidden
- Merb::ControllerExceptions::GatewayTimeout
- Merb::ControllerExceptions::Gone
- Merb::ControllerExceptions::HTTPVersionNotSupported
- Merb::ControllerExceptions::Informational
- Merb::ControllerExceptions::InternalServerError
- Merb::ControllerExceptions::LayoutNotFound
- Merb::ControllerExceptions::LengthRequired
- Merb::ControllerExceptions::MethodNotAllowed
- Merb::ControllerExceptions::MovedPermanently
- Merb::ControllerExceptions::MovedTemporarily
- Merb::ControllerExceptions::MultiPartParseError
- Merb::ControllerExceptions::MultipleChoices
- Merb::ControllerExceptions::NoContent
- Merb::ControllerExceptions::NonAuthoritativeInformation
- Merb::ControllerExceptions::NotAcceptable
- Merb::ControllerExceptions::NotFound
- Merb::ControllerExceptions::NotImplemented
- Merb::ControllerExceptions::NotModified
- Merb::ControllerExceptions::OK
- Merb::ControllerExceptions::PartialContent
- Merb::ControllerExceptions::PaymentRequired
- Merb::ControllerExceptions::PreconditionFailed
- Merb::ControllerExceptions::ProxyAuthenticationRequired
- Merb::ControllerExceptions::Redirection
- Merb::ControllerExceptions::RequestEntityTooLarge
- Merb::ControllerExceptions::RequestRangeNotSatisfiable
- Merb::ControllerExceptions::RequestTimeout
- Merb::ControllerExceptions::RequestURITooLarge
- Merb::ControllerExceptions::ResetContent
- Merb::ControllerExceptions::SeeOther
- Merb::ControllerExceptions::ServerError
- Merb::ControllerExceptions::ServiceUnavailable
- Merb::ControllerExceptions::Successful
- Merb::ControllerExceptions::SwitchingProtocols
- Merb::ControllerExceptions::TemplateNotFound
- Merb::ControllerExceptions::TemporaryRedirect
- Merb::ControllerExceptions::Unauthorized
- Merb::ControllerExceptions::UnsupportedMediaType
- Merb::ControllerExceptions::UseProxy
- Merb::ControllerMixin
- Merb::CookieSession
- Merb::CookieSession::CookieOverflow
- Merb::CookieSession::TamperedWithCookie
- Merb::Cookies
- Merb::CookiesMixin
- Merb::CookiesMixin::RequestMixin
- Merb::Counter
- Merb::Dispatcher
- Merb::Dispatcher::DefaultException
- Merb::Dispatcher::DefaultExceptionHelper
- Merb::GlobalHelpers
- Merb::InlineTemplates
- Merb::Logger
- Merb::MemcacheSession
- Merb::MemcacheStore
- Merb::MemorySession
- Merb::MemorySessionStore
- Merb::Parse
- Merb::Plugins
- Merb::Rack
- Merb::Rack::AbstractAdapter
- Merb::Rack::Adapter
- Merb::Rack::Application
- Merb::Rack::ConditionalGet
- Merb::Rack::Console
- Merb::Rack::ContentLength
- Merb::Rack::DeferrableMiddleware
- Merb::Rack::Ebb
- Merb::Rack::EventedMongrel
- Merb::Rack::FastCGI
- Merb::Rack::Handler
- Merb::Rack::Handler::Mongrel
- Merb::Rack::Head
- Merb::Rack::Helpers
- Merb::Rack::Irb
- Merb::Rack::Middleware
- Merb::Rack::Mongrel
- Merb::Rack::PathPrefix
- Merb::Rack::Profiler
- Merb::Rack::Runner
- Merb::Rack::Static
- Merb::Rack::StreamWrapper
- Merb::Rack::SwiftipliedMongrel
- Merb::Rack::Thin
- Merb::Rack::ThinTurbo
- Merb::Rack::Tracer
- Merb::Rack::WEBrick
- Merb::RenderMixin
- Merb::RenderMixin::ClassMethods
- Merb::Request
- Merb::ReservedError
- Merb::Responder
- Merb::ResponderMixin
- Merb::ResponderMixin::ClassMethods
- Merb::ResponderMixin::ContentTypeAlreadySet
- Merb::Router
- Merb::Router::Behavior
- Merb::Router::Behavior::Error
- Merb::Router::Behavior::Proxy
- Merb::Router::CachedProc
- Merb::Router::GenerationError
- Merb::Router::NotCompiledError
- Merb::Router::Resources
- Merb::Router::RouteNotFound
- Merb::Server
- Merb::Session
- Merb::SessionContainer
- Merb::SessionMixin
- Merb::SessionMixin::NoSessionContainer
- Merb::SessionMixin::RequestMixin
- Merb::SessionMixin::RequestMixin::ClassMethods
- Merb::SessionMixin::SessionOverflow
- Merb::SessionStoreContainer
- Merb::System
- Merb::System::PortablePoller
- Merb::Template
- Merb::Template::Erubis
- Merb::Template::Erubis::Mixin
- Merb::Test
- Merb::Test::ControllerHelper
- Merb::Test::Cookie
- Merb::Test::CookieJar
- Merb::Test::ExampleGroup
- Merb::Test::Helpers
- Merb::Test::MakeRequest
- Merb::Test::Matchers
- Merb::Test::MultipartRequestHelper
- Merb::Test::MultipartRequestHelper::FileParam
- Merb::Test::MultipartRequestHelper::Param
- Merb::Test::MultipartRequestHelper::Post
- Merb::Test::RequestHelper
- Merb::Test::RequestHelper::CookieJar
- Merb::Test::RequestHelper::FakeRequest
- Merb::Test::RouteHelper
- Merb::Test::Rspec
- Merb::Test::Rspec::ControllerMatchers
- Merb::Test::Rspec::ControllerMatchers::BeError
- Merb::Test::Rspec::ControllerMatchers::BeRedirect
- Merb::Test::Rspec::ControllerMatchers::Provide
- Merb::Test::Rspec::RouteMatchers
- Merb::Test::Rspec::RouteMatchers::ParameterMatcher
- Merb::Test::Rspec::RouteMatchers::RouteToMatcher
- Merb::Test::ViewHelper
- Merb::Test::WebratHelper
- Merb::Worker
- Erubis
- Erubis::Basic
- Erubis::Basic::Converter
- Erubis::BlockAwareEnhancer
- Erubis::BlockAwareEruby
- Erubis::MEruby
- Spec
- Spec::Matchers
- Spec::Matchers::MatcherDSL
- Spec::Runner
- Spec::Runner::Formatter
- Spec::Runner::Formatter::BaseTextFormatter
- Gem
- Gem::Dependency
- Hpricot
- Hpricot::Elem
- Mongrel
- Mongrel::HttpResponse
- Class
- Exception
- Hash
- Kernel
- MemCache
- Memcached
- Object
- String
- Time

No matching classes.

# Merb::Server

Server encapsulates the management of Merb daemons.

### Public Class Methods

_change_privilege(user, group=user) click to toggle source

Change privileges of the process to the specified user and group.

#### Parameters

user<String> | The user to change the process to.
group<String> | The group to change the process to.

#### Alternatives

If group is left out, the user will be used as the group.

:api: private

    # File lib/merb-core/server.rb, line 324
    def _change_privilege(user, group=user)
      Merb.logger.warn! "Changing privileges to #{user}:#{group}"

      uid, gid = Process.euid, Process.egid

      begin
        target_uid = Etc.getpwnam(user).uid
      rescue ArgumentError => e
        Merb.fatal!("Failed to change to user #{user}, does the user exist?", e)
        return false
      end

      begin
        target_gid = Etc.getgrnam(group).gid
      rescue ArgumentError => e
        Merb.fatal!("Failed to change to group #{group}, does the group exist?", e)
        return false
      end

      if (uid != target_uid) || (gid != target_gid)
        # Change process ownership
        Process.initgroups(user, target_gid)
        Process::GID.change_privilege(target_gid)
        Process::UID.change_privilege(target_uid)
      end
      true
    rescue Errno::EPERM => e
      Merb.fatal! "Permission denied for changing user:group to #{user}:#{group}.", e
      false
    end

add_irb_trap() click to toggle source

Add trap to enter IRB on SIGINT. Process exit if second SIGINT is received.

:api: private

    # File lib/merb-core/server.rb, line 358
    def add_irb_trap
      Merb.trap("INT") do
        if @interrupted
          Merb.logger.warn! "Interrupt received a second time, exiting!\n"
          exit
        end

        @interrupted = true
        Merb.logger.warn! "Interrupt a second time to quit."
        Kernel.sleep 1.5
        ARGV.clear # Avoid passing args to IRB

        if @irb.nil?
          require "irb"
          IRB.setup(nil)
          @irb = IRB::Irb.new(nil)
          IRB.conf[:MAIN_CONTEXT] = @irb.context
        end

        Merb.trap(:INT) { @irb.signal_handle }
        catch(:IRB_EXIT) { @irb.eval_input }

        Merb.logger.warn! "Exiting from IRB mode back into server mode."
        @interrupted = false
        add_irb_trap
      end
    end

alive?(port) click to toggle source

#### Parameters

port<~to_s> | The port to check for Merb instances on.

#### Returns

Boolean | True if Merb is running on the specified port.

:api: private

    # File lib/merb-core/server.rb, line 54
    def alive?(port)
      pidfile = pid_file(port)
      pid     = pid_in_file(pidfile)
      Process.kill(0, pid)
      true
    rescue Errno::ESRCH, Errno::ENOENT
      false
    rescue Errno::EACCES => e
      Merb.fatal!("You don't have access to the PID file at #{pidfile}: #{e.message}")
    end

bootup() click to toggle source

Starts up Merb by running the bootloader and starting the adapter.

:api: private

    # File lib/merb-core/server.rb, line 168
    def bootup
      Merb.trap("TERM") { shutdown }

      Merb.logger.warn! "Running bootloaders..." if Merb::Config[:verbose]
      BootLoader.run
      Merb.logger.warn! "Starting Rack adapter..." if Merb::Config[:verbose]
      Merb.adapter.start(Merb::Config.to_hash)
    end

change_privilege() click to toggle source

Change process user/group to those specified in Merb::Config.

:api: private

    # File lib/merb-core/server.rb, line 190
    def change_privilege
      if Merb::Config[:user] && Merb::Config[:group]
        Merb.logger.verbose! "About to change privilege to group "              "#{Merb::Config[:group]} and user #{Merb::Config[:user]}"
        _change_privilege(Merb::Config[:user], Merb::Config[:group])
      elsif Merb::Config[:user]
        Merb.logger.verbose! "About to change privilege to user "              "#{Merb::Config[:user]}"
        _change_privilege(Merb::Config[:user])
      else
        return true
      end
    end

daemonize(port) click to toggle source

#### Parameters

port<~to_s> | The port of the Merb process to daemonize.

:api: private

    # File lib/merb-core/server.rb, line 141
    def daemonize(port)
      Merb.logger.warn! "About to fork..." if Merb::Config[:verbose]
      fork do
        Process.setsid
        exit if fork
        Merb.logger.warn! "In #{Process.pid}" if Merb.logger
        File.umask 0000
        STDIN.reopen "/dev/null"
        STDOUT.reopen "/dev/null", "a"
        STDERR.reopen STDOUT
        begin
          Dir.chdir Merb::Config[:merb_root]
        rescue Errno::EACCES => e
          Merb.fatal! "You specified Merb root as #{Merb::Config[:merb_root]}, "                "yet the current user does not have access to it. ", e
        end
        at_exit { remove_pid_file(port) }
        Merb::Config[:port] = port
        bootup
      end
    rescue NotImplementedError => e
      Merb.fatal! "Daemonized mode is not supported on your platform. ", e
    end

kill(port, sig = "INT") click to toggle source

#### Parameters

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

#### Alternatives

If you pass "all" as the port, the signal will be sent to all Merb processes.

:api: private

    # File lib/merb-core/server.rb, line 88
    def kill(port, sig = "INT")
      if sig.is_a?(Integer)
        sig = Signal.list.invert[sig]
      end

      Merb::BootLoader::BuildFramework.run

      # If we kill the master, then the workers should be reaped also.
      if %(main master all).include?(port)
        # If a graceful exit is requested then send INT to the master process.
        #
        # Otherwise read pids from pid files and try to kill each process in turn.
        kill_pid(sig, pid_file("main")) if sig == "INT"
      else
        kill_pid(sig, pid_file(port))
      end
    end

kill_pid(sig, file) click to toggle source

Sends the provided signal to the process pointed at by the provided pid file. :api: private

    # File lib/merb-core/server.rb, line 108
    def kill_pid(sig, file)
      begin
        pid = pid_in_file(file)
        Merb.logger.fatal! "Killing pid #{pid} with #{sig}"
        Process.kill(sig, pid)
        FileUtils.rm(file) if File.exist?(file)
      rescue Errno::EINVAL
        Merb.logger.fatal! "Failed to kill PID #{pid} with #{sig}: '#{sig}' is an invalid "              "or unsupported signal number."
      rescue Errno::EPERM
        Merb.logger.fatal! "Failed to kill PID #{pid} with #{sig}: Insufficient permissions."
      rescue Errno::ESRCH
        FileUtils.rm file
        Merb.logger.fatal! "Failed to kill PID #{pid} with #{sig}: Process is "              "deceased or zombie."
      rescue Errno::EACCES => e
        Merb.logger.fatal! e.message
      rescue Errno::ENOENT => e
        # This should not cause abnormal exit, which is why
        # we do not use Merb.fatal but instead just log with max level.
        Merb.logger.fatal! "Could not find a PID file at #{file}. "              "Most likely the process is no longer running and the pid file was not cleaned up."
      rescue Exception => e
        if !e.is_a?(SystemExit)
          Merb.logger.fatal! "Failed to kill PID #{pid.inspect} with #{sig.inspect}: #{e.message}"
        end
      end
    end

pid_file(port) click to toggle source

Gets the pid file for the specified port/socket.

#### Parameters

port<~to_s> | The port/socket of the Merb process to whom the the PID file belongs to.

#### Returns

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 lib/merb-core/server.rb, line 290
    def pid_file(port)
      pidfile = Merb::Config[:pid_file] || (Merb.log_path / "merb.%s.pid")
      pidfile % port
    end

pid_files() click to toggle source

Get a list of the pid files.

#### Returns

Array | List of pid file paths. If not running clustered, the array contains a single path.

:api: private

    # File lib/merb-core/server.rb, line 302
    def pid_files
      if Merb::Config[:pid_file]
        if Merb::Config[:cluster]
          Dir[Merb::Config[:pid_file] % "*"]
        else
          [ Merb::Config[:pid_file] ]
        end
      else
        Dir[Merb.log_path / "merb.*.pid"]
      end
     end

pid_in_file(pidfile) click to toggle source

:api: private

    # File lib/merb-core/server.rb, line 66
    def pid_in_file(pidfile)
      File.read(pidfile).chomp.to_i
    end

remove_pid(port) click to toggle source

Delete the pidfile for the specified port/socket.

:api: private

    # File lib/merb-core/server.rb, line 245
    def remove_pid(port)
      FileUtils.rm(pid_file(port)) if File.file?(pid_file(port))
    end

remove_pid_file(port) click to toggle source

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.

#### Parameters

port<~to_s> | The port of the Merb process to whom the the PID file belongs to.

#### Alternatives

If Merb::Config has been specified, that will be used instead of the port/socket based PID file.

:api: private

    # File lib/merb-core/server.rb, line 217
    def remove_pid_file(port)
      pidfile = pid_file(port)
      if File.exist?(pidfile)
        Merb.logger.warn! "Removing pid file #{pidfile} (port/socket: #{port})..."
        FileUtils.rm(pidfile)
      end
    end

shutdown(status = 0) click to toggle source

Shut down Merb, reap any workers if necessary.

:api: private

    # File lib/merb-core/server.rb, line 180
    def shutdown(status = 0)
      # reap_workers does exit but may not be called...
      Merb::BootLoader::LoadClasses.reap_workers(status) if Merb::Config[:fork_for_class_load]
      # which is why we exit explicitly here
      exit(status)
    end

start(port, cluster=nil) click to toggle source

Start a Merb server, in either foreground, daemonized or cluster mode.

#### Parameters

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.

#### Alternatives

If cluster is left out, then one process will be started. This process will be daemonized if Merb::Config is true.

:api: private

    # File lib/merb-core/server.rb, line 23
    def start(port, cluster=nil)

      @port = port
      @cluster = cluster

      if Merb::Config[:daemonize]
        pidfile = pid_file(port)
        pid = File.read(pidfile).chomp.to_i if File.exist?(pidfile)

        unless alive?(@port)
          remove_pid_file(@port)
          Merb.logger.warn! "Daemonizing..." if Merb::Config[:verbose]
          daemonize(@port)
        else
          Merb.fatal! "Merb is already running on port #{port}.\n"                "\e[0m   \e[1;31;47mpid file: \e[34;47m#{pidfile}"                "\e[1;31;47m, process id is \e[34;47m#{pid}."
        end
      else
        bootup
      end
    end

store_details(port = nil) click to toggle source

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.

#### Parameters

port<~to_s> | The port of the Merb process to whom the the PID file belongs to.

#### Alternatives

If Merb::Config has been specified, that will be used instead of the port/socket based PID file.

:api: private

    # File lib/merb-core/server.rb, line 262
    def store_details(port = nil)
      file = pid_file(port)
      begin
        FileUtils.mkdir_p(File.dirname(file))
      rescue Errno::EACCES => e
        Merb.fatal! "Failed to store Merb logs in #{File.dirname(file)}, "              "permission denied. ", e
      end
      Merb.logger.warn! "Storing pid #{Process.pid} file to #{file}..." if Merb::Config[:verbose]
      begin
        File.open(file, 'w'){ |f| f.write(Process.pid.to_s) }
      rescue Errno::EACCES => e
        Merb.fatal! "Failed to access #{file}, permission denied.", e
      end
    end

store_pid(port) click to toggle source

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.

#### Parameters

port<~to_s> | The port of the Merb process to whom the the PID file belongs to.

#### Alternatives

If Merb::Config has been specified, that will be used instead of the port/socket based PID file.

:api: private

    # File lib/merb-core/server.rb, line 238
    def store_pid(port)
      store_details(port)
    end

[Validate]

Generated with the Darkfish Rdoc Generator 2.