Starman
view release on metacpan or search on metacpan
lib/Starman/Server.pm view on Meta::CPAN
host => '*', # default host
proto => $options->{ssl} ? 'ssl' : 'tcp', # default proto
serialize => ( $^O =~ m!(linux|darwin|bsd|cygwin)$! ) ? 'none' : 'flock',
min_servers => $options->{min_servers} || $workers,
min_spare_servers => $options->{min_spare_servers} || $workers - 1,
max_spare_servers => $options->{max_spare_servers} || $workers - 1,
max_servers => $options->{max_servers} || $workers,
max_requests => $options->{max_requests} || 1000,
user => $options->{user} || $>,
group => $options->{group} || $),
listen => $options->{backlog} || 1024,
check_for_waiting => 1,
no_client_stdout => 1,
%extra
);
}
sub pre_loop_hook {
my $self = shift;
my $port = $self->{server}->{port}->[0];
my $proto = $port->{proto} eq 'ssl' ? 'https' :
$port->{proto} eq 'unix' ? 'unix' :
'http';
$self->{options}{server_ready}->({
host => $port->{host},
port => $port->{port},
proto => $proto,
server_software => 'Starman',
}) if $self->{options}{server_ready};
register_sig(
TTIN => sub { $self->{server}->{$_}++ for qw( min_servers max_servers ) },
TTOU => sub { $self->{server}->{$_}-- for qw( min_servers max_servers ) },
QUIT => sub { $self->server_close(1) },
);
}
sub server_close {
my($self, $quit) = @_;
if ($quit) {
$self->log(2, $self->log_time . " Received QUIT. Running a graceful shutdown\n");
$self->{server}->{$_} = 0 for qw( min_servers max_servers );
$self->hup_children;
while (1) {
Net::Server::SIG::check_sigs();
$self->coordinate_children;
last if !keys %{$self->{server}{children}};
sleep 1;
}
$self->log(2, $self->log_time . " Worker processes cleaned up\n");
}
$self->SUPER::server_close();
}
sub run_parent {
my $self = shift;
$0 = "starman master " . join(" ", @{$self->{options}{argv} || []})
if $self->{options}{proctitle};
no warnings 'redefine';
local *Net::Server::PreFork::register_sig = sub {
my %args = @_;
delete $args{QUIT};
Net::Server::SIG::register_sig(%args);
};
$self->SUPER::run_parent(@_);
}
# The below methods run in the child process
sub child_init_hook {
my $self = shift;
srand();
if ($self->{options}->{psgi_app_builder}) {
DEBUG && warn "[$$] Initializing the PSGI app\n";
$self->{app} = $self->{options}->{psgi_app_builder}->();
}
$0 = "starman worker " . join(" ", @{$self->{options}{argv} || []})
if $self->{options}{proctitle};
}
sub post_accept_hook {
my $self = shift;
$self->{client} = {
headerbuf => '',
inputbuf => '',
keepalive => 1,
};
}
sub dispatch_request {
my ($self, $env) = @_;
# Run PSGI apps
my $res = Plack::Util::run_app($self->{app}, $env);
if (ref $res eq 'CODE') {
$res->(sub { $self->_finalize_response($env, $_[0]) });
} else {
$self->_finalize_response($env, $res);
}
}
sub process_request {
my $self = shift;
my $conn = $self->{server}->{client};
if ($conn->NS_proto eq 'TCP') {
setsockopt($conn, IPPROTO_TCP, TCP_NODELAY, 1)
or die $!;
}
while ( $self->{client}->{keepalive} ) {
last if !$conn->connected;
# Read until we see all headers
last if !$self->_read_headers;
my $env = {
REMOTE_ADDR => $self->{server}->{peeraddr},
REMOTE_HOST => $self->{server}->{peerhost} || $self->{server}->{peeraddr},
REMOTE_PORT => $self->{server}->{peerport} || 0,
SERVER_NAME => $self->{server}->{sockaddr} || 0, # XXX: needs to be resolved?
SERVER_PORT => $self->{server}->{sockport} || 0,
SCRIPT_NAME => '',
'psgi.version' => [ 1, 1 ],
'psgi.errors' => *STDERR,
'psgi.url_scheme' => ($conn->NS_proto eq 'SSL' ? 'https' : 'http'),
'psgi.nonblocking' => Plack::Util::FALSE,
'psgi.streaming' => Plack::Util::TRUE,
'psgi.run_once' => Plack::Util::FALSE,
'psgi.multithread' => Plack::Util::FALSE,
'psgi.multiprocess' => Plack::Util::TRUE,
'psgix.io' => $conn,
'psgix.input.buffered' => Plack::Util::TRUE,
'psgix.harakiri' => Plack::Util::TRUE,
( run in 0.688 second using v1.01-cache-2.11-cpan-e93a5daba3e )