### Home Classes Methods

### In Files

- lib/phusion_passenger/request_handler/thread_handler.rb
- lib/phusion_passenger/request_handler.rb

### Parent

Object

### Namespace

- CLASS PhusionPassenger::RequestHandler::ThreadHandler

### Methods

- ::new
- #cleanup
- #main_loop
- #main_loop_running?
- #soft_shutdown
- #start_main_loop_thread

### Included Modules

- PhusionPassenger::DebugLogging
- PhusionPassenger::Utils

### Class/Module Index

Quicksearch

- PhusionPassenger
- PhusionPassenger::AbstractInstaller
- PhusionPassenger::AbstractInstaller::Abort
- PhusionPassenger::AbstractInstaller::CommandError
- PhusionPassenger::AdminTools
- PhusionPassenger::AdminTools::MemoryStats
- PhusionPassenger::AdminTools::MemoryStats::Process
- PhusionPassenger::AdminTools::ServerInstance
- PhusionPassenger::AdminTools::ServerInstance::CorruptedDirectoryError
- PhusionPassenger::AdminTools::ServerInstance::GenerationsAbsentError
- PhusionPassenger::AdminTools::ServerInstance::Group
- PhusionPassenger::AdminTools::ServerInstance::Process
- PhusionPassenger::AdminTools::ServerInstance::RoleDeniedError
- PhusionPassenger::AdminTools::ServerInstance::StaleDirectoryError
- PhusionPassenger::AdminTools::ServerInstance::Stats
- PhusionPassenger::AdminTools::ServerInstance::UnsupportedGenerationStructureVersionError
- PhusionPassenger::AnalyticsLogger
- PhusionPassenger::AnalyticsLogger::Connection
- PhusionPassenger::AnalyticsLogger::Lock
- PhusionPassenger::AnalyticsLogger::Log
- PhusionPassenger::ClassicRails
- PhusionPassenger::ClassicRails::CGIFixed
- PhusionPassenger::ClassicRails::ThreadHandlerExtension
- PhusionPassenger::ConsoleTextTemplate
- PhusionPassenger::DebugLogging
- PhusionPassenger::LoaderSharedHelpers
- PhusionPassenger::MessageChannel
- PhusionPassenger::MessageChannel::InvalidHashError
- PhusionPassenger::MessageClient
- PhusionPassenger::NativeSupportLoader
- PhusionPassenger::Packaging
- PhusionPassenger::PlatformInfo
- PhusionPassenger::PlatformInfo::ApacheDetector
- PhusionPassenger::PlatformInfo::ApacheDetector::Result
- PhusionPassenger::PlatformInfo::Depcheck
- PhusionPassenger::PlatformInfo::Depcheck::ConsoleRunner
- PhusionPassenger::PlatformInfo::Depcheck::Dependency
- PhusionPassenger::PlatformInfo::RuntimeError
- PhusionPassenger::Plugin
- PhusionPassenger::PreloaderSharedHelpers
- PhusionPassenger::Rack
- PhusionPassenger::Rack::OutOfBandGc
- PhusionPassenger::Rack::ThreadHandlerExtension
- PhusionPassenger::Rails3Extensions
- PhusionPassenger::Rails3Extensions::AnalyticsLogging
- PhusionPassenger::Rails3Extensions::AnalyticsLogging::ACExtension
- PhusionPassenger::Rails3Extensions::AnalyticsLogging::ASBenchmarkableExtension
- PhusionPassenger::Rails3Extensions::AnalyticsLogging::ExceptionLogger
- PhusionPassenger::RequestHandler
- PhusionPassenger::RequestHandler::ThreadHandler
- PhusionPassenger::RequestHandler::ThreadHandler::Interrupted
- PhusionPassenger::SharedConstants
- PhusionPassenger::Standalone
- PhusionPassenger::Standalone::AppFinder
- PhusionPassenger::Standalone::Command
- PhusionPassenger::Standalone::ConfigFile
- PhusionPassenger::Standalone::ConfigFile::DisallowedContextError
- PhusionPassenger::Standalone::HelpCommand
- PhusionPassenger::Standalone::Main
- PhusionPassenger::Standalone::PackageRuntimeCommand
- PhusionPassenger::Standalone::RuntimeInstaller
- PhusionPassenger::Standalone::RuntimeLocator
- PhusionPassenger::Standalone::StartCommand
- PhusionPassenger::Standalone::StatusCommand
- PhusionPassenger::Standalone::StopCommand
- PhusionPassenger::Standalone::Utils
- PhusionPassenger::Standalone::VersionCommand
- PhusionPassenger::Utils
- PhusionPassenger::Utils::AnsiColors
- PhusionPassenger::Utils::FileSystemWatcher
- PhusionPassenger::Utils::FileSystemWatcher::DirInfo
- PhusionPassenger::Utils::FileSystemWatcher::FileInfo
- PhusionPassenger::Utils::GeneratorTest
- PhusionPassenger::Utils::HostsFileParser
- PhusionPassenger::Utils::JSON
- PhusionPassenger::Utils::JSON::Generator
- PhusionPassenger::Utils::ParserTest
- PhusionPassenger::Utils::TeeInput
- PhusionPassenger::Utils::TmpIO
- PhusionPassenger::Utils::UnseekableSocket
- CommonLibraryBuilder
- Exception
- GC
- IO
- Object
- Signal

No matching classes.

# PhusionPassenger::RequestHandler

### Constants

BACKLOG_SIZE
HARD_TERMINATION_SIGNAL

  Signal which will cause the Rails application to exit immediately.

SOFT_TERMINATION_SIGNAL

  Signal which will cause the Rails application to exit as soon as it's done processing a request.

### Attributes

concurrency[R]
connect_password[RW]

A password with which clients must authenticate. Default is unauthenticated.

server_sockets[R]

A hash containing all server sockets that this request handler listens on. The hash is in the form of:

    {
       name1 => [socket_address1, socket_type1, socket1],
       name2 => [socket_address2, socket_type2, socket2],
       ...
    }

`name` is a Symbol. `socket_addressx` is the address of the socket, `socket_typex` is the socket's type (either 'unix' or 'tcp') and `socketx` is the actual socket IO objec. There's guaranteed to be at least one server socket, namely one with the name `:main`.

soft_termination_linger_time[RW]

If a soft termination signal was received, then the main loop will quit the given amount of seconds after the last time a connection was accepted. Defaults to 3 seconds.

### Public Class Methods

new(owner_pipe, options = {}) click to toggle source

Create a new RequestHandler with the given owner pipe. `owner_pipe` must be the readable part of a pipe IO object.

Additionally, the following options may be given:

- detach_key

- connect_password

- pool_account_username

- pool_account_password_base64

    # File lib/phusion_passenger/request_handler.rb, line 87
    def initialize(owner_pipe, options = {})
            require_option(options, "app_group_name")
            install_options_as_ivars(self, options,
                    "app",
                    "app_group_name",
                    "connect_password",
                    "detach_key",
                    "analytics_logger",
                    "pool_account_username"
            )
            @thread_handler = options["thread_handler"] || ThreadHandler
            @concurrency = 1
            if options["pool_account_password_base64"]
                    @pool_account_password = options["pool_account_password_base64"].unpack('m').first
            end

            #############
            #############

            @server_sockets = {}

            if should_use_unix_sockets?
                    @main_socket_address, @main_socket = create_unix_socket_on_filesystem
            else
                    @main_socket_address, @main_socket = create_tcp_socket
            end
            @server_sockets[:main] = {
                    :address     => @main_socket_address,
                    :socket      => @main_socket,
                    :protocol    => :session,
                    :concurrency => @concurrency
            }

            @http_socket_address, @http_socket = create_tcp_socket
            @server_sockets[:http] = {
                    :address     => @http_socket_address,
                    :socket      => @http_socket,
                    :protocol    => :http,
                    :concurrency => 1
            }

            @owner_pipe = owner_pipe
            @options = options
            @previous_signal_handlers = {}
            @main_loop_generation  = 0
            @main_loop_thread_lock = Mutex.new
            @main_loop_thread_cond = ConditionVariable.new
            @threads = []
            @threads_mutex = Mutex.new
            @soft_termination_linger_time = 3
            @main_loop_running  = false

            #############
    end

### Public Instance Methods

cleanup() click to toggle source

Clean up temporary stuff created by the request handler.

If the main loop was started by main_loop, then this method may only be called after the main loop has exited.

If the main loop was started by start_main_loop_thread, then this method may be called at any time, and it will stop the main loop thread.

    # File lib/phusion_passenger/request_handler.rb, line 149
    def cleanup
            if @main_loop_thread
                    @main_loop_thread_lock.synchronize do
                            @graceful_termination_pipe[1].close rescue nil
                    end
                    @main_loop_thread.join
            end
            @server_sockets.each_value do |value|
                    address, type, socket = value
                    socket.close rescue nil
                    if type == 'unix'
                            File.unlink(address) rescue nil
                    end
            end
            @owner_pipe.close rescue nil
    end

main_loop() click to toggle source

Enter the request handler's main loop.

    # File lib/phusion_passenger/request_handler.rb, line 174
    def main_loop
            debug("Entering request handler main loop")
            reset_signal_handlers
            begin
                    @graceful_termination_pipe = IO.pipe
                    @graceful_termination_pipe[0].close_on_exec!
                    @graceful_termination_pipe[1].close_on_exec!

                    @main_loop_thread_lock.synchronize do
                            @main_loop_generation += 1
                            @main_loop_running = true
                            @main_loop_thread_cond.broadcast

                            @select_timeout = nil

                            @selectable_sockets = []
                            @server_sockets.each_value do |value|
                                    socket = value[2]
                                    @selectable_sockets << socket if socket
                            end
                            @selectable_sockets << @owner_pipe
                            @selectable_sockets << @graceful_termination_pipe[0]
                    end

                    install_useful_signal_handlers
                    start_threads
                    wait_until_termination_requested
                    wait_until_all_threads_are_idle
                    terminate_threads
                    debug("Request handler main loop exited normally")

            rescue EOFError
                    # Exit main loop.
                    trace(2, "Request handler main loop interrupted by EOFError exception")
            rescue Interrupt
                    # Exit main loop.
                    trace(2, "Request handler main loop interrupted by Interrupt exception")
            rescue SignalException => signal
                    trace(2, "Request handler main loop interrupted by SignalException")
                    if signal.message != HARD_TERMINATION_SIGNAL &&
                       signal.message != SOFT_TERMINATION_SIGNAL
                            raise
                    end
            rescue Exception => e
                    trace(2, "Request handler main loop interrupted by #{e.class} exception")
                    raise
            ensure
                    debug("Exiting request handler main loop")
                    revert_signal_handlers
                    @main_loop_thread_lock.synchronize do
                            @graceful_termination_pipe[1].close rescue nil
                            @graceful_termination_pipe[0].close rescue nil
                            @selectable_sockets = []
                            @main_loop_generation += 1
                            @main_loop_running = false
                            @main_loop_thread_cond.broadcast
                    end
            end
    end

main_loop_running?() click to toggle source

Check whether the main loop's currently running.

    # File lib/phusion_passenger/request_handler.rb, line 167
    def main_loop_running?
            @main_loop_thread_lock.synchronize do
                    return @main_loop_running
            end
    end

soft_shutdown() click to toggle source

Remove this request handler from the application pool so that no new connections will come in. Then make the main loop quit a few seconds after the last time a connection came in. This all is to ensure that no connections come in while we're shutting down.

May only be called while the main loop is running. May be called from any thread.

    # File lib/phusion_passenger/request_handler.rb, line 258
    def soft_shutdown
            @soft_termination_linger_thread ||= Thread.new do
                    debug("Soft termination initiated")
                    if @detach_key && @pool_account_username && @pool_account_password
                            client = MessageClient.new(@pool_account_username, @pool_account_password)
                            begin
                                    client.pool_detach_process_by_key(@detach_key)
                            ensure
                                    client.close
                            end
                    end
                    wait_until_all_threads_are_idle
                    debug("Soft terminating in #{@soft_termination_linger_time} seconds")
                    sleep @soft_termination_linger_time
                    @graceful_termination_pipe[1].close rescue nil
            end
    end

start_main_loop_thread() click to toggle source

Start the main loop in a new thread. This thread will be stopped by cleanup.

    # File lib/phusion_passenger/request_handler.rb, line 235
    def start_main_loop_thread
            current_generation = @main_loop_generation
            @main_loop_thread = Thread.new do
                    begin
                            main_loop
                    rescue Exception => e
                            print_exception(self.class, e)
                    end
            end
            @main_loop_thread_lock.synchronize do
                    while @main_loop_generation == current_generation
                            @main_loop_thread_cond.wait(@main_loop_thread_lock)
                    end
            end
    end

[Validate]

Generated with the Darkfish Rdoc Generator 2.