class PhusionPassenger::Standalone::StartCommand

Public Class Methods

description() click to toggle source
# File lib/phusion_passenger/standalone/start_command.rb, line 38
def self.description
        return "Start Phusion Passenger Standalone."
end
new(args) click to toggle source
# File lib/phusion_passenger/standalone/start_command.rb, line 42
def initialize(args)
        super(args)
        @console_mutex = Mutex.new
        @termination_pipe = IO.pipe
        @threads = []
        @interruptable_threads = []
        @plugin = PhusionPassenger::Plugin.new('standalone/start_command', self, @options)
end

Public Instance Methods

run() click to toggle source
# File lib/phusion_passenger/standalone/start_command.rb, line 51
def run
        parse_my_options
        sanity_check_options

        PhusionPassenger.require_passenger_lib 'standalone/runtime_locator'
        @runtime_locator = RuntimeLocator.new(@options[:runtime_dir],
                @options[:nginx_version])
        ensure_runtime_installed
        set_stdout_stderr_binmode
        exit if @options[:runtime_check_only]
        require_app_finder
        @app_finder = AppFinder.new(@args, @options)
        @apps = @app_finder.scan
        @options = @app_finder.global_options
        determine_various_resource_locations
        @plugin.call_hook(:found_apps, @apps)

        extra_controller_options = {}
        @plugin.call_hook(:before_creating_nginx_controller, extra_controller_options)
        create_nginx_controller(extra_controller_options)

        begin
                start_nginx
                show_intro_message
                if @options[:daemonize]
                        if PlatformInfo.ruby_supports_fork?
                                daemonize
                        else
                                daemonize_without_fork
                        end
                end
                Thread.abort_on_exception = true
                @plugin.call_hook(:nginx_started, @nginx)
                ########################
                ########################
                touch_temp_dir_in_background
                watch_log_files_in_background if should_watch_logs?
                wait_until_nginx_has_exited if should_wait_until_nginx_has_exited?
        rescue Interrupt
                begin_shutdown
                stop_threads
                stop_nginx
                exit 2
        rescue SignalException => signal
                begin_shutdown
                stop_threads
                stop_nginx
                if signal.message == 'SIGINT' || signal.message == 'SIGTERM'
                        exit 2
                else
                        raise
                end
        rescue Exception => e
                begin_shutdown
                stop_threads
                stop_nginx
                raise
        ensure
                begin_shutdown
                begin
                        stop_threads
                ensure
                        finalize_shutdown
                end
        end
ensure
        @plugin.call_hook(:cleanup)
end

Private Instance Methods

begin_shutdown() click to toggle source
# File lib/phusion_passenger/standalone/start_command.rb, line 635
def begin_shutdown
        return if @shutting_down
        @shutting_down = 1
        trap("INT", &method(:signal_during_shutdown))
        trap("TERM", &method(:signal_during_shutdown))
end
check_port(host_name, port) click to toggle source
# File lib/phusion_passenger/standalone/start_command.rb, line 351
def check_port(host_name, port)
        channel = java.nio.channels.SocketChannel.open
        begin
                address = java.net.InetSocketAddress.new(host_name, port)
                channel.configure_blocking(false)
                if channel.connect(address)
                        return true
                end

                deadline = Time.now.to_f + 0.1
                done = false
                while true
                        begin
                                if channel.finish_connect
                                        return true
                                end
                        rescue java.net.ConnectException => e
                                if e.message =~ /Connection refused/i
                                        return false
                                else
                                        throw e
                                end
                        end

                        # Not done connecting and no error.
                        sleep 0.01
                        if Time.now.to_f >= deadline
                                return false
                        end
                end
        ensure
                channel.close
        end
end
check_port_availability() click to toggle source
# File lib/phusion_passenger/standalone/start_command.rb, line 425
def check_port_availability
        if !@options[:socket_file] && check_port(@options[:address], @options[:port])
                error "The address #{@options[:address]}:#{@options[:port]} is already " <<
                      "in use by another process, perhaps another Phusion Passenger " <<
                      "Standalone instance.\n\n" <<
                      "If you want to run this Phusion Passenger Standalone instance on " <<
                      "another port, use the -p option, like this:\n\n" <<
                      "  passenger start -p #{@options[:port] + 1}"
                exit 1
        end
end
check_port_bind_permission_and_display_sudo_suggestion() click to toggle source

Most platforms don't allow non-root processes to bind to a port lower than 1024. Check whether this is the case for the current platform and if so, tell the user that it must re-run Phusion Passenger Standalone with sudo.

# File lib/phusion_passenger/standalone/start_command.rb, line 327
def check_port_bind_permission_and_display_sudo_suggestion
        if !@options[:socket_file] && @options[:port] < 1024 && Process.euid != 0
                begin
                        TCPServer.new('127.0.0.1', @options[:port]).close
                rescue Errno::EACCES
                        PhusionPassenger.require_passenger_lib 'platform_info/ruby'
                        myself = %xwhoami`.strip
                        error "Only the 'root' user can run this program on port #{@options[:port]}. " <<
                              "You are currently running as '#{myself}'. Please re-run this program " <<
                              "with root privileges with the following command:\n\n" <<

                              "  #{PlatformInfo.ruby_sudo_command} passenger start #{@original_args.join(' ')} --user=#{myself}\n\n" <<

                              "Don't forget the '--user' part! That will make Phusion Passenger Standalone " <<
                              "drop root privileges and switch to '#{myself}' after it has obtained " <<
                              "port #{@options[:port]}."
                        exit 1
                end
        end
end
check_port_with_protocol(address, port, protocol) click to toggle source
# File lib/phusion_passenger/standalone/start_command.rb, line 386
def check_port_with_protocol(address, port, protocol)
        begin
                socket = Socket.new(protocol, Socket::Constants::SOCK_STREAM, 0)
                sockaddr = Socket.pack_sockaddr_in(port, address)
                begin
                        socket.connect_nonblock(sockaddr)
                rescue Errno::ENOENT, Errno::EINPROGRESS, Errno::EAGAIN, Errno::EWOULDBLOCK
                        if select(nil, [socket], nil, 0.1)
                                begin
                                        socket.connect_nonblock(sockaddr)
                                rescue Errno::EISCONN
                                rescue Errno::EINVAL
                                        if PlatformInfo.os_name =~ /freebsd/i
                                                raise Errno::ECONNREFUSED
                                        else
                                                raise
                                        end
                                end
                        else
                                raise Errno::ECONNREFUSED
                        end
                end
                return true
        rescue Errno::ECONNREFUSED
                return false
        ensure
                socket.close if socket && !socket.closed?
        end
end
compose_ip_and_port(ip, port) click to toggle source
# File lib/phusion_passenger/standalone/start_command.rb, line 737
def compose_ip_and_port(ip, port)
        if ip =~ /:/
                # IPv6
                return "[#{ip}]:#{port}"
        else
                return "#{ip}:#{port}"
        end
end
daemonize() click to toggle source
# File lib/phusion_passenger/standalone/start_command.rb, line 552
def daemonize
        pid = fork
        if pid
                # Parent
                exit!(0)
        else
                # Child
                trap "HUP", "IGNORE"
                STDIN.reopen("/dev/null", "r")
                STDOUT.reopen(@options[:log_file], "a")
                STDERR.reopen(@options[:log_file], "a")
                STDOUT.sync = true
                STDERR.sync = true
                Process.setsid
        end
end
daemonize_without_fork() click to toggle source
# File lib/phusion_passenger/standalone/start_command.rb, line 546
def daemonize_without_fork
        STDERR.puts "Unable to daemonize using the current Ruby interpreter " +
                "(#{PlatformInfo.ruby_command}) because it does not support forking."
        exit 1
end
default_group_for(username) click to toggle source
# File lib/phusion_passenger/standalone/start_command.rb, line 746
def default_group_for(username)
        user = Etc.getpwnam(username)
        group = Etc.getgrgid(user.gid)
        return group.name
end
ensure_runtime_installed() click to toggle source
# File lib/phusion_passenger/standalone/start_command.rb, line 482
def ensure_runtime_installed
        if @runtime_locator.everything_installed?
                if !File.exist?(@runtime_locator.find_nginx_binary)
                        error "The web helper binary '#{@runtime_locator.find_nginx_binary}' does not exist."
                        exit 1
                end
        else
                if !@runtime_locator.find_support_dir && PhusionPassenger.natively_packaged?
                        error "Your Phusion Passenger Standalone installation is broken: the support " +
                                "files could not be found. Please reinstall Phusion Passenger Standalone. " +
                                "If this problem persists, please contact your packager."
                        exit 1
                end
                install_runtime(@runtime_locator) || exit(1)
                @runtime_locator.reload
        end
end
finalize_shutdown() click to toggle source
# File lib/phusion_passenger/standalone/start_command.rb, line 642
def finalize_shutdown
        @shutting_down = nil
        trap("INT", "DEFAULT")
        trap("TERM", "DEFAULT")
end
install_runtime(runtime_locator) click to toggle source
# File lib/phusion_passenger/standalone/start_command.rb, line 466
def install_runtime(runtime_locator)
        PhusionPassenger.require_passenger_lib 'standalone/runtime_installer'
        installer = RuntimeInstaller.new(
                :targets     => runtime_locator.install_targets,
                :support_dir => runtime_locator.support_dir_install_destination,
                :nginx_dir   => runtime_locator.nginx_binary_install_destination,
                :lib_dir     => runtime_locator.find_lib_dir || runtime_locator.support_dir_install_destination,
                :nginx_version     => @options[:nginx_version],
                :nginx_tarball     => @options[:nginx_tarball],
                :binaries_url_root => @options[:binaries_url_root],
                :download_binaries => @options.fetch(:download_binaries, true),
                :dont_compile_runtime => @options[:dont_compile_runtime],
                :plugin      => @plugin)
        return installer.run
end
listen_url() click to toggle source

Returns the URL that Nginx will be listening on.

# File lib/phusion_passenger/standalone/start_command.rb, line 446
def listen_url
        if @options[:socket_file]
                return @options[:socket_file]
        else
                if @options[:ssl] && !@options[:ssl_port]
                        scheme = "https"
                else
                        scheme = "http"
                end
                result = "#{scheme}://"
                if @options[:port] == 80
                        result << @options[:address]
                else
                        result << compose_ip_and_port(@options[:address], @options[:port])
                end
                result << "/"
                return result
        end
end
nginx_listen_address(options = @options, for_ping_port = false) click to toggle source

Config file template helpers ####

# File lib/phusion_passenger/standalone/start_command.rb, line 716
def nginx_listen_address(options = @options, for_ping_port = false)
        if options[:socket_file]
                return "unix:" + File.expand_path(options[:socket_file])
        else
                if for_ping_port
                        port = options[:ping_port]
                else
                        port = options[:port]
                end
                return compose_ip_and_port(options[:address], port)
        end
end
nginx_listen_address_with_ssl_port(options = @options) click to toggle source
# File lib/phusion_passenger/standalone/start_command.rb, line 729
def nginx_listen_address_with_ssl_port(options = @options)
        if options[:socket_file]
                return "unix:" + File.expand_path(options[:socket_file])
        else
                return compose_ip_and_port(options[:address], options[:ssl_port])
        end
end
parse_my_options() click to toggle source
# File lib/phusion_passenger/standalone/start_command.rb, line 125
def parse_my_options
        description = "Starts Phusion Passenger Standalone and serve one or more Ruby web applications."
        parse_options!("start [directory]", description) do |opts|
                opts.on("-a", "--address HOST", String,
                        wrap_desc("Bind to HOST address (default: #{@options[:address]})")) do |value|
                        @options[:address] = value
                        @options[:tcp_explicitly_given] = true
                end
                opts.on("-p", "--port NUMBER", Integer,
                        wrap_desc("Use the given port number (default: #{@options[:port]})")) do |value|
                        @options[:port] = value
                        @options[:tcp_explicitly_given] = true
                end
                opts.on("-S", "--socket FILE", String,
                        wrap_desc("Bind to Unix domain socket instead of TCP socket")) do |value|
                        @options[:socket_file] = value
                end

                opts.separator ""
                opts.on("-e", "--environment ENV", String,
                        wrap_desc("Framework environment (default: #{@options[:environment]})")) do |value|
                        @options[:environment] = value
                end
                opts.on("-R", "--rackup FILE", String,
                        wrap_desc("Consider application a Ruby Rack app, and use the given rackup file")) do |value|
                        @options[:app_type] = "rack"
                        @options[:startup_file] = value
                end
                opts.on("--app-type NAME", String,
                        wrap_desc("Force app to be detected as the given type")) do |value|
                        @options[:app_type] = value
                end
                opts.on("--startup-file FILENAME", String,
                        wrap_desc("Force given startup file to be used")) do |value|
                        @options[:startup_file] = value
                end
                opts.on("--max-pool-size NUMBER", Integer,
                        wrap_desc("Maximum number of application processes (default: #{@options[:max_pool_size]})")) do |value|
                        @options[:max_pool_size] = value
                end
                opts.on("--min-instances NUMBER", Integer,
                        wrap_desc("Minimum number of processes per application (default: #{@options[:min_instances]})")) do |value|
                        @options[:min_instances] = value
                end
                opts.on("--spawn-method NAME", String,
                        wrap_desc("The spawn method to use (default: #{@options[:spawn_method]})")) do |value|
                        @options[:spawn_method] = value
                end
                opts.on("--concurrency-model NAME", String,
                        wrap_desc("The concurrency model to use, either 'process' or 'thread' (default: #{@options[:concurrency_model]}) (Enterprise only)")) do |value|
                        @options[:concurrency_model] = value
                end
                opts.on("--thread-count NAME", Integer,
                        wrap_desc("The number of threads to use when using the 'thread' concurrency model (default: #{@options[:thread_count]}) (Enterprise only)")) do |value|
                        @options[:thread_count] = value
                end
                opts.on("--rolling-restarts",
                        wrap_desc("Enable rolling restarts (Enterprise only)")) do
                        @options[:rolling_restarts] = true
                end
                opts.on("--resist-deployment-errors",
                        wrap_desc("Enable deployment error resistance (Enterprise only)")) do
                        @options[:resist_deployment_errors] = true
                end
                opts.on("--friendly-error-pages",
                        wrap_desc("Turn on friendly error pages")) do
                        @options[:friendly_error_pages] = true
                end
                opts.on("--no-friendly-error-pages",
                        wrap_desc("Turn off friendly error pages")) do
                        @options[:friendly_error_pages] = false
                end
                opts.on("--ssl",
                        wrap_desc("Enable SSL support")) do
                        @options[:ssl] = true
                end
                opts.on("--ssl-certificate PATH", String,
                        wrap_desc("Specify the SSL certificate path")) do |val|
                        @options[:ssl_certificate] = File.expand_path(val)
                end
                opts.on("--ssl-certificate-key PATH", String,
                        wrap_desc("Specify the SSL key path")) do |val|
                        @options[:ssl_certificate_key] = File.expand_path(val)
                end
                opts.on("--ssl-port PORT", Integer,
                        wrap_desc("Listen for SSL on this port, while listening for HTTP on the normal port")) do |val|
                        @options[:ssl_port] = val
                end
                opts.on("--static-files-dir PATH", String,
                        wrap_desc("Specify the static files dir")) do |val|
                        @options[:static_files_dir] = File.expand_path(val)
                end
                opts.on("--restart-dir PATH", String,
                        wrap_desc("Specify the restart dir")) do |val|
                        @options[:restart_dir] = File.expand_path(val)
                end
                opts.on("--union-station-gateway HOST:PORT", String,
                        wrap_desc("Specify Union Station Gateway host and port")) do |value|
                        host, port = value.split(":", 2)
                        port = port.to_i
                        port = 443 if port == 0
                        @options[:union_station_gateway_address] = host
                        @options[:union_station_gateway_port] = port.to_i
                end
                opts.on("--union-station-key KEY", String,
                        wrap_desc("Specify Union Station key")) do |value|
                        @options[:union_station_key] = value
                end

                opts.separator ""
                opts.on("--ping-port NUMBER", Integer,
                        wrap_desc("Use the given port number for checking whether Nginx is alive (default: same as the normal port)")) do |value|
                        @options[:ping_port] = value
                end
                @plugin.call_hook(:parse_options, opts)

                opts.separator ""
                opts.on("-d", "--daemonize",
                        wrap_desc("Daemonize into the background")) do
                        @options[:daemonize] = true
                end
                opts.on("--user USERNAME", String,
                        wrap_desc("User to run as. Ignored unless running as root.")) do |value|
                        @options[:user] = value
                end
                opts.on("--log-file FILENAME", String,
                        wrap_desc("Where to write log messages (default: console, or /dev/null when daemonized)")) do |value|
                        @options[:log_file] = value
                end
                opts.on("--pid-file FILENAME", String,
                        wrap_desc("Where to store the PID file")) do |value|
                        @options[:pid_file] = value
                end
                opts.on("--temp-dir PATH", String,
                        wrap_desc("Use the given temp dir")) do |value|
                        ENV['TMPDIR'] = value
                        @options[:temp_dir] = value
                end

                opts.separator ""
                opts.on("--nginx-bin FILENAME", String,
                        wrap_desc("Nginx binary to use as core")) do |value|
                        @options[:nginx_bin] = value
                end
                opts.on("--nginx-version VERSION", String,
                        wrap_desc("Nginx version to use as core (default: #{@options[:nginx_version]})")) do |value|
                        @options[:nginx_version] = value
                end
                opts.on("--nginx-tarball FILENAME", String,
                        wrap_desc("If Nginx needs to be installed, then the given tarball will " +
                                  "be used instead of downloading from the Internet")) do |value|
                        @options[:nginx_tarball] = File.expand_path(value)
                end
                opts.on("--nginx-config-template FILENAME", String,
                        wrap_desc("The template to use for generating the Nginx config file")) do |value|
                        @options[:nginx_config_template] = File.expand_path(value)
                end
                opts.on("--binaries-url-root URL", String,
                        wrap_desc("If Nginx needs to be installed, then the specified URL will be " +
                                  "checked for binaries prior to a local build.")) do |value|
                        @options[:binaries_url_root] = value
                end
                opts.on("--no-download-binaries",
                        wrap_desc("Never download binaries")) do
                        @options[:download_binaries] = false
                end
                opts.on("--runtime-dir DIRECTORY", String,
                        wrap_desc("Directory to use for Phusion Passenger Standalone runtime files")) do |value|
                        @options[:runtime_dir] = File.expand_path(value)
                end
                opts.on("--runtime-check-only",
                        wrap_desc("Quit after checking whether the Phusion Passenger Standalone runtime files are installed")) do
                        @options[:runtime_check_only] = true
                end
                opts.on("--no-compile-runtime",
                        wrap_desc("Abort if runtime must be compiled")) do
                        @options[:dont_compile_runtime] = true
                end
        end
        @plugin.call_hook(:done_parsing_options)
end
require_file_utils() click to toggle source
# File lib/phusion_passenger/standalone/start_command.rb, line 121
def require_file_utils
        require 'fileutils' unless defined?(FileUtils)
end
sanity_check_options() click to toggle source
# File lib/phusion_passenger/standalone/start_command.rb, line 307
def sanity_check_options
        if @options[:tcp_explicitly_given] && @options[:socket_file]
                error "You cannot specify both --address/--port and --socket. Please choose either one."
                exit 1
        end
        if @options[:ssl] && !@options[:ssl_certificate]
                error "You specified --ssl. Please specify --ssl-certificate as well."
                exit 1
        end
        if @options[:ssl] && !@options[:ssl_certificate_key]
                error "You specified --ssl. Please specify --ssl-certificate-key as well."
                exit 1
        end
        check_port_bind_permission_and_display_sudo_suggestion
        check_port_availability
end
set_stdout_stderr_binmode() click to toggle source
# File lib/phusion_passenger/standalone/start_command.rb, line 500
def set_stdout_stderr_binmode
        # We already set STDOUT and STDERR to binmode in bin/passenger, which
        # fixes https://github.com/phusion/passenger-ruby-heroku-demo/issues/11.
        # However RuntimeInstaller sets them to UTF-8, so here we set them back.
        STDOUT.binmode
        STDERR.binmode
end
should_wait_until_nginx_has_exited?() click to toggle source
# File lib/phusion_passenger/standalone/start_command.rb, line 441
def should_wait_until_nginx_has_exited?
        return !@options[:daemonize] || @app_finder.multi_mode?
end
should_watch_logs?() click to toggle source
# File lib/phusion_passenger/standalone/start_command.rb, line 437
def should_watch_logs?
        return !@options[:daemonize] && @options[:log_file] != "/dev/null"
end
show_intro_message() click to toggle source
# File lib/phusion_passenger/standalone/start_command.rb, line 529
def show_intro_message
        puts "=============== Phusion Passenger Standalone web server started ==============="
        puts "PID file: #{@options[:pid_file]}"
        puts "Log file: #{@options[:log_file]}"
        puts "Environment: #{@options[:environment]}"
        puts "Accessible via: #{listen_url}"

        puts
        if @options[:daemonize]
                puts "Serving in the background as a daemon."
        else
                puts "You can stop Phusion Passenger Standalone by pressing Ctrl-C."
        end
        puts "Problems? Check #{STANDALONE_DOC_URL}#troubleshooting"
        puts "==============================================================================="
end
signal_during_shutdown(signal) click to toggle source
# File lib/phusion_passenger/standalone/start_command.rb, line 648
def signal_during_shutdown(signal)
        if @shutting_down == 1
                @shutting_down += 1
                puts "Ignoring signal #{signal} during shutdown. Send it again to force exit."
        else
                exit!(1)
        end
end
start_nginx() click to toggle source
# File lib/phusion_passenger/standalone/start_command.rb, line 508
def start_nginx
        begin
                @nginx.start
        rescue DaemonController::AlreadyStarted
                begin
                        pid = @nginx.pid
                rescue SystemCallError, IOError
                        pid = nil
                end
                if pid
                        error "Phusion Passenger Standalone is already running on PID #{pid}."
                else
                        error "Phusion Passenger Standalone is already running."
                end
                exit 1
        rescue DaemonController::StartError => e
                error "Could not start Passenger Nginx core:\n#{e}"
                exit 1
        end
end
stop_nginx() click to toggle source
# File lib/phusion_passenger/standalone/start_command.rb, line 689
def stop_nginx
        @console_mutex.synchronize do
                STDOUT.write("Stopping web server...")
                STDOUT.flush
                @nginx.stop
                STDOUT.puts " done"
                STDOUT.flush
        end
end
stop_threads() click to toggle source
# File lib/phusion_passenger/standalone/start_command.rb, line 699
def stop_threads
        if !@termination_pipe[1].closed?
                @termination_pipe[1].write("x")
                @termination_pipe[1].close
        end
        @interruptable_threads.each do |thread|
                thread.terminate
        end
        @interruptable_threads = []
        @threads.each do |thread|
                thread.join
        end
        @threads = []
end
stop_touching_temp_dir_in_background() click to toggle source
# File lib/phusion_passenger/standalone/start_command.rb, line 657
def stop_touching_temp_dir_in_background
        if @toucher
                begin
                        Process.kill('TERM', @toucher.pid)
                rescue Errno::ESRCH, Errno::ECHILD
                end
                @toucher.close
        end
end
touch_temp_dir_in_background() click to toggle source
# File lib/phusion_passenger/standalone/start_command.rb, line 622
def touch_temp_dir_in_background
        result = system("#{@runtime_locator.find_agents_dir}/TempDirToucher",
                @temp_dir,
                "--cleanup",
                "--daemonize",
                "--pid-file", "#{@temp_dir}/temp_dir_toucher.pid",
                "--log-file", @options[:log_file])
        if !result
                error "Cannot start #{@runtime_locator.find_agents_dir}/TempDirToucher"
                exit 1
        end
end
wait_on_termination_pipe(timeout) click to toggle source

Wait until the termination pipe becomes readable (a hint for threads to shut down), or until the timeout has been reached. Returns true if the termination pipe became readable, false if the timeout has been reached.

# File lib/phusion_passenger/standalone/start_command.rb, line 572
def wait_on_termination_pipe(timeout)
        ios = select([@termination_pipe[0]], nil, nil, timeout)
        return !ios.nil?
end
wait_until_nginx_has_exited() click to toggle source
# File lib/phusion_passenger/standalone/start_command.rb, line 667
def wait_until_nginx_has_exited
        # Since Nginx is not our child process (it daemonizes or we daemonize)
        # we cannot use Process.waitpid to wait for it. A busy-sleep-loop with
        # Process.kill(0, pid) isn't very efficient. Instead we do this:
        #
        # Connect to Nginx and wait until Nginx disconnects the socket because of
        # timeout. Keep doing this until we can no longer connect.
        while true
                if @options[:socket_file]
                        socket = UNIXSocket.new(@options[:socket_file])
                else
                        socket = TCPSocket.new(@options[:address], nginx_ping_port)
                end
                begin
                        socket.read rescue nil
                ensure
                        socket.close rescue nil
                end
        end
rescue Errno::ECONNREFUSED, Errno::ECONNRESET
end
watch_log_file(log_file) click to toggle source
# File lib/phusion_passenger/standalone/start_command.rb, line 577
def watch_log_file(log_file)
        if File.exist?(log_file)
                backward = 0
        else
                # tail bails out if the file doesn't exist, so wait until it exists.
                while !File.exist?(log_file)
                        sleep 1
                end
                backward = 10
        end

        IO.popen("tail -f -n #{backward} \"#{log_file}\"", "rb") do |f|
                begin
                        while true
                                begin
                                        line = f.readline
                                        @console_mutex.synchronize do
                                                STDOUT.write(line)
                                                STDOUT.flush
                                        end
                                rescue EOFError
                                        break
                                end
                        end
                ensure
                        Process.kill('TERM', f.pid) rescue nil
                end
        end
end
watch_log_files_in_background() click to toggle source
# File lib/phusion_passenger/standalone/start_command.rb, line 607
def watch_log_files_in_background
        @apps.each do |app|
                thread = Thread.new do
                        watch_log_file("#{app[:root]}/log/#{@options[:environment]}.log")
                end
                @threads << thread
                @interruptable_threads << thread
        end
        thread = Thread.new do
                watch_log_file(@options[:log_file])
        end
        @threads << thread
        @interruptable_threads << thread
end