class RBMK::Server

Public Class Methods

new() click to toggle source
# File lib/rbmk/server.rb, line 7
def initialize
        $master = true
        @arvg0 = File.basename Process.argv0
        @workers = {}
end

Protected Class Methods

host() click to toggle source
# File lib/rbmk/server.rb, line 35
def self.host; '127.0.0.1' end
port() click to toggle source
# File lib/rbmk/server.rb, line 36
def self.port; 8389 end
upstream() click to toggle source
# File lib/rbmk/server.rb, line 38
def self.upstream
        require 'rbmk/upstream'
        RBMK::Upstream.new
end

Public Instance Methods

start() click to toggle source
# File lib/rbmk/server.rb, line 13
def start
        require 'rbmk/version'
        $log.info sprintf('rbmk version %s (codename %p) is warming up in an orange glow', VERSION, CODENAME)
        require 'socket'
        @upstream = self.class.upstream
        $log.debug sprintf('Listening on %s:%s', self.class.host, self.class.port)
        @socket = TCPServer.new self.class.host, self.class.port
        $0 = sprintf '%s master at %s:%s', @arvg0, self.class.host, self.class.port
        Signal.trap('CHLD') { raise SignalException, 'CHLD' }
        loop { accept }
ensure
        @socket.close rescue nil
        $log.debug sprintf('Disposing of workers: %p', @workers.keys)
        Signal.trap('CHLD') {} # we'll bury them in synchronous fashion
        Thread.abort_on_exception = true
        @workers.each { |pid,_| Thread.new { kill pid } }
        sleep(0.1) while Thread.list.count > 1 # make sure everyone is dead
        $log.info 'Shutdown sequence complete'
end

Protected Instance Methods

accept() click to toggle source
# File lib/rbmk/server.rb, line 43
def accept
        peer = Peer.new @socket.accept
        $log.info 'Connection from %s' % peer
        if pid = fork then
                peer.close
                @workers[pid] = true
        else
                $log.debug 'Worker started'
                @socket.close
                act_as_a_child_for peer
        end
rescue SignalException
        $log.debug 'Trapped %p' % ($!.signm.empty? ? 'SIGINT' : $!.signm)
        case $!.signo
                when SIGCHLD then reap
                when SIGINT, SIGHUP, SIGTERM then exit
                when SIGQUIT then
                        $log.debug 'Committing emergency suicide'
                        exit!
                else raise $!
        end
end
act_as_a_child_for(peer) click to toggle source
# File lib/rbmk/server.rb, line 66
def act_as_a_child_for peer
        Signal.trap 'CHLD', 'SYSTEM_DEFAULT'
        $master = false
        remove_instance_variable :@workers
        $0 = sprintf '%s worker for %s', @arvg0, peer
        serve peer
rescue SignalException
        $log.debug 'Trapped %p' % ($!.signm.empty? ? 'SIGINT' : $!.signm)
        raise $!
rescue Exception
        $!.log
ensure
        $log.debug 'Terminating'
        exit!
end
kill(pid) click to toggle source
# File lib/rbmk/server.rb, line 87
def kill pid
        $log.debug 'Killing worker %s' % pid
        Process.kill 'TERM', pid
        Process.wait pid
        $log.debug 'Worker %s will not be a problem anymore' % pid
rescue Errno::ESRCH
        $log.debug 'Somehow worker %s was not alive' % pid
rescue Errno::ECHILD
        $log.debug 'Worker %s has suddenly disappeared' % pid
end
reap() click to toggle source
# File lib/rbmk/server.rb, line 98
def reap
        loop {
                pid, status = Process.wait2 -1, Process::WNOHANG
                raise Errno::ECHILD if pid.nil?
                @workers.delete pid
                $log.debug 'Reaped %s' % pid
        }
rescue Errno::ECHILD
end
serve(peer) click to toggle source
# File lib/rbmk/server.rb, line 82
def serve peer
        require 'rbmk/worker'
        Worker.hire peer, @upstream
end