Initial Commit
This commit is contained in:
131
database/perl/vendor/lib/Mojo/Server/CGI.pm
vendored
Normal file
131
database/perl/vendor/lib/Mojo/Server/CGI.pm
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
package Mojo::Server::CGI;
|
||||
use Mojo::Base 'Mojo::Server';
|
||||
|
||||
has 'nph';
|
||||
|
||||
sub run {
|
||||
my $self = shift;
|
||||
|
||||
my $tx = $self->build_tx;
|
||||
my $req = $tx->req->parse(\%ENV);
|
||||
$tx->local_port($ENV{SERVER_PORT})->remote_address($ENV{REMOTE_ADDR});
|
||||
|
||||
# Request body (may block if we try to read too much)
|
||||
binmode STDIN;
|
||||
my $len = $req->headers->content_length;
|
||||
until ($req->is_finished) {
|
||||
my $chunk = ($len && $len < 131072) ? $len : 131072;
|
||||
last unless my $read = STDIN->read(my $buffer, $chunk, 0);
|
||||
$req->parse($buffer);
|
||||
last if ($len -= $read) <= 0;
|
||||
}
|
||||
|
||||
$self->emit(request => $tx);
|
||||
|
||||
# Response start-line
|
||||
STDOUT->autoflush(1);
|
||||
binmode STDOUT;
|
||||
my $res = $tx->res->fix_headers;
|
||||
return undef if $self->nph && !_write($res, 'get_start_line_chunk');
|
||||
|
||||
# Response headers
|
||||
my $code = $res->code || 404;
|
||||
my $msg = $res->message || $res->default_message;
|
||||
$res->headers->status("$code $msg") unless $self->nph;
|
||||
return undef unless _write($res, 'get_header_chunk');
|
||||
|
||||
# Response body
|
||||
return undef unless $tx->is_empty || _write($res, 'get_body_chunk');
|
||||
|
||||
# Finish transaction
|
||||
$tx->closed;
|
||||
|
||||
return $res->code;
|
||||
}
|
||||
|
||||
sub _write {
|
||||
my ($res, $method) = @_;
|
||||
|
||||
my $offset = 0;
|
||||
while (1) {
|
||||
|
||||
# No chunk yet, try again
|
||||
sleep 1 and next unless defined(my $chunk = $res->$method($offset));
|
||||
|
||||
# End of part
|
||||
last unless my $len = length $chunk;
|
||||
|
||||
# Make sure we can still write
|
||||
$offset += $len;
|
||||
return undef unless STDOUT->opened;
|
||||
print STDOUT $chunk;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
=encoding utf8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Mojo::Server::CGI - CGI server
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Mojo::Server::CGI;
|
||||
|
||||
my $cgi = Mojo::Server::CGI->new;
|
||||
$cgi->unsubscribe('request')->on(request => sub ($cgi, $tx) {
|
||||
|
||||
# Request
|
||||
my $method = $tx->req->method;
|
||||
my $path = $tx->req->url->path;
|
||||
|
||||
# Response
|
||||
$tx->res->code(200);
|
||||
$tx->res->headers->content_type('text/plain');
|
||||
$tx->res->body("$method request for $path!");
|
||||
|
||||
# Resume transaction
|
||||
$tx->resume;
|
||||
});
|
||||
$cgi->run;
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
L<Mojo::Server::CGI> is a simple and portable implementation of L<RFC 3875|https://tools.ietf.org/html/rfc3875>.
|
||||
|
||||
See L<Mojolicious::Guides::Cookbook/"DEPLOYMENT"> for more.
|
||||
|
||||
=head1 EVENTS
|
||||
|
||||
L<Mojo::Server::CGI> inherits all events from L<Mojo::Server>.
|
||||
|
||||
=head1 ATTRIBUTES
|
||||
|
||||
L<Mojo::Server::CGI> inherits all attributes from L<Mojo::Server> and implements the following new ones.
|
||||
|
||||
=head2 nph
|
||||
|
||||
my $bool = $cgi->nph;
|
||||
$cgi = $cgi->nph($bool);
|
||||
|
||||
Activate non-parsed header mode.
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
L<Mojo::Server::CGI> inherits all methods from L<Mojo::Server> and implements the following new ones.
|
||||
|
||||
=head2 run
|
||||
|
||||
my $status = $cgi->run;
|
||||
|
||||
Run CGI.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Mojolicious>, L<Mojolicious::Guides>, L<https://mojolicious.org>.
|
||||
|
||||
=cut
|
||||
521
database/perl/vendor/lib/Mojo/Server/Daemon.pm
vendored
Normal file
521
database/perl/vendor/lib/Mojo/Server/Daemon.pm
vendored
Normal file
@@ -0,0 +1,521 @@
|
||||
package Mojo::Server::Daemon;
|
||||
use Mojo::Base 'Mojo::Server';
|
||||
|
||||
use Carp qw(croak);
|
||||
use Mojo::IOLoop;
|
||||
use Mojo::Transaction::WebSocket;
|
||||
use Mojo::URL;
|
||||
use Mojo::Util qw(term_escape);
|
||||
use Mojo::WebSocket qw(server_handshake);
|
||||
use Scalar::Util qw(weaken);
|
||||
|
||||
use constant DEBUG => $ENV{MOJO_SERVER_DEBUG} || 0;
|
||||
|
||||
has acceptors => sub { [] };
|
||||
has [qw(backlog max_clients silent)];
|
||||
has inactivity_timeout => sub { $ENV{MOJO_INACTIVITY_TIMEOUT} // 30 };
|
||||
has ioloop => sub { Mojo::IOLoop->singleton };
|
||||
has keep_alive_timeout => sub { $ENV{MOJO_KEEP_ALIVE_TIMEOUT} // 5 };
|
||||
has listen => sub { [split /,/, $ENV{MOJO_LISTEN} || 'http://*:3000'] };
|
||||
has max_requests => 100;
|
||||
|
||||
sub DESTROY {
|
||||
return if Mojo::Util::_global_destruction();
|
||||
my $self = shift;
|
||||
my $loop = $self->ioloop;
|
||||
$loop->remove($_) for keys %{$self->{connections} // {}}, @{$self->acceptors};
|
||||
}
|
||||
|
||||
sub ports { [map { $_[0]->ioloop->acceptor($_)->port } @{$_[0]->acceptors}] }
|
||||
|
||||
sub run {
|
||||
my $self = shift;
|
||||
|
||||
# Make sure the event loop can be stopped in regular intervals
|
||||
my $loop = $self->ioloop;
|
||||
my $int = $loop->recurring(1 => sub { });
|
||||
local $SIG{INT} = local $SIG{TERM} = sub { $loop->stop };
|
||||
$self->start->ioloop->start;
|
||||
$loop->remove($int);
|
||||
}
|
||||
|
||||
sub start {
|
||||
my $self = shift;
|
||||
|
||||
my $loop = $self->ioloop;
|
||||
if (my $max = $self->max_clients) { $loop->max_connections($max) }
|
||||
|
||||
# Resume accepting connections
|
||||
if (my $servers = $self->{servers}) {
|
||||
push @{$self->acceptors}, $loop->acceptor(delete $servers->{$_}) for keys %$servers;
|
||||
}
|
||||
|
||||
# Start listening
|
||||
elsif (!@{$self->acceptors}) {
|
||||
$self->app->server($self);
|
||||
$self->_listen($_) for @{$self->listen};
|
||||
}
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub stop {
|
||||
my $self = shift;
|
||||
|
||||
# Suspend accepting connections but keep listen sockets open
|
||||
my $loop = $self->ioloop;
|
||||
while (my $id = shift @{$self->acceptors}) {
|
||||
my $server = $self->{servers}{$id} = $loop->acceptor($id);
|
||||
$loop->remove($id);
|
||||
$server->stop;
|
||||
}
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub _build_tx {
|
||||
my ($self, $id, $c) = @_;
|
||||
|
||||
my $tx = $self->build_tx->connection($id);
|
||||
$tx->res->headers->server('Mojolicious (Perl)');
|
||||
my $handle = $self->ioloop->stream($id)->timeout($self->inactivity_timeout)->handle;
|
||||
unless ($handle->isa('IO::Socket::UNIX')) {
|
||||
$tx->local_address($handle->sockhost)->local_port($handle->sockport);
|
||||
$tx->remote_address($handle->peerhost)->remote_port($handle->peerport);
|
||||
}
|
||||
$tx->req->url->base->scheme('https') if $c->{tls};
|
||||
|
||||
weaken $self;
|
||||
$tx->on(
|
||||
request => sub {
|
||||
my $tx = shift;
|
||||
|
||||
my $req = $tx->req;
|
||||
if (my $error = $req->error) { $self->_debug($id, $error->{message}) }
|
||||
|
||||
# WebSocket
|
||||
if ($req->is_handshake) {
|
||||
my $ws = $self->{connections}{$id}{next} = Mojo::Transaction::WebSocket->new(handshake => $tx);
|
||||
$self->emit(request => server_handshake $ws);
|
||||
}
|
||||
|
||||
# HTTP
|
||||
else { $self->emit(request => $tx) }
|
||||
|
||||
# Last keep-alive request or corrupted connection
|
||||
my $c = $self->{connections}{$id};
|
||||
$tx->res->headers->connection('close') if ($c->{requests} || 1) >= $self->max_requests || $req->error;
|
||||
|
||||
$tx->on(resume => sub { $self->_write($id) });
|
||||
$self->_write($id);
|
||||
}
|
||||
);
|
||||
|
||||
# Kept alive if we have more than one request on the connection
|
||||
return ++$c->{requests} > 1 ? $tx->kept_alive(1) : $tx;
|
||||
}
|
||||
|
||||
sub _close {
|
||||
my ($self, $id) = @_;
|
||||
if (my $tx = $self->{connections}{$id}{tx}) { $tx->closed }
|
||||
delete $self->{connections}{$id};
|
||||
}
|
||||
|
||||
sub _debug { $_[0]->app->log->debug($_[2]) if $_[0]{connections}{$_[1]}{tx} }
|
||||
|
||||
sub _finish {
|
||||
my ($self, $id) = @_;
|
||||
|
||||
# Always remove connection for WebSockets
|
||||
my $c = $self->{connections}{$id};
|
||||
return unless my $tx = $c->{tx};
|
||||
return $self->_remove($id) if $tx->is_websocket;
|
||||
|
||||
# Finish transaction
|
||||
delete($c->{tx})->closed;
|
||||
|
||||
# Upgrade connection to WebSocket
|
||||
if (my $ws = delete $c->{next}) {
|
||||
|
||||
# Successful upgrade
|
||||
if ($ws->handshake->res->code == 101) {
|
||||
$c->{tx} = $ws->established(1);
|
||||
weaken $self;
|
||||
$ws->on(resume => sub { $self->_write($id) });
|
||||
$self->_write($id);
|
||||
}
|
||||
|
||||
# Failed upgrade
|
||||
else { $ws->closed }
|
||||
}
|
||||
|
||||
# Close connection if necessary
|
||||
return $self->_remove($id) if $tx->error || !$tx->keep_alive;
|
||||
|
||||
# Build new transaction for leftovers
|
||||
if (length(my $leftovers = $tx->req->content->leftovers)) {
|
||||
$tx = $c->{tx} = $self->_build_tx($id, $c);
|
||||
$tx->server_read($leftovers);
|
||||
}
|
||||
|
||||
# Keep-alive connection
|
||||
$self->ioloop->stream($id)->timeout($self->keep_alive_timeout) unless $c->{tx};
|
||||
}
|
||||
|
||||
sub _listen {
|
||||
my ($self, $listen) = @_;
|
||||
|
||||
my $url = Mojo::URL->new($listen);
|
||||
my $proto = $url->protocol;
|
||||
croak qq{Invalid listen location "$listen"} unless $proto eq 'http' || $proto eq 'https' || $proto eq 'http+unix';
|
||||
|
||||
my $query = $url->query;
|
||||
my $options = {backlog => $self->backlog};
|
||||
$options->{$_} = $query->param($_) for qw(fd single_accept reuse);
|
||||
if ($proto eq 'http+unix') { $options->{path} = $url->host }
|
||||
else {
|
||||
if ((my $host = $url->host) ne '*') { $options->{address} = $host }
|
||||
if (my $port = $url->port) { $options->{port} = $port }
|
||||
}
|
||||
$options->{"tls_$_"} = $query->param($_) for qw(ca ciphers version);
|
||||
/^(.*)_(cert|key)$/ and $options->{"tls_$2"}{$1} = $query->param($_) for @{$query->names};
|
||||
if (my $cert = $query->param('cert')) { $options->{'tls_cert'}{''} = $cert }
|
||||
if (my $key = $query->param('key')) { $options->{'tls_key'}{''} = $key }
|
||||
my $verify = $query->param('verify');
|
||||
$options->{tls_verify} = hex $verify if defined $verify;
|
||||
my $tls = $options->{tls} = $proto eq 'https';
|
||||
|
||||
weaken $self;
|
||||
push @{$self->acceptors}, $self->ioloop->server(
|
||||
$options => sub {
|
||||
my ($loop, $stream, $id) = @_;
|
||||
|
||||
$self->{connections}{$id} = {tls => $tls};
|
||||
warn "-- Accept $id (@{[$stream->handle->peerhost]})\n" if DEBUG;
|
||||
$stream->timeout($self->inactivity_timeout);
|
||||
|
||||
$stream->on(close => sub { $self && $self->_close($id) });
|
||||
$stream->on(error => sub { $self && $self->app->log->error(pop) && $self->_close($id) });
|
||||
$stream->on(read => sub { $self->_read($id => pop) });
|
||||
$stream->on(timeout => sub { $self->_debug($id, 'Inactivity timeout') });
|
||||
}
|
||||
);
|
||||
|
||||
return if $self->silent;
|
||||
$self->app->log->info(qq{Listening at "$url"});
|
||||
$query->pairs([]);
|
||||
$url->host('127.0.0.1') if $url->host eq '*';
|
||||
say 'Web application available at ', $options->{path} // $url;
|
||||
}
|
||||
|
||||
sub _read {
|
||||
my ($self, $id, $chunk) = @_;
|
||||
|
||||
# Make sure we have a transaction
|
||||
my $c = $self->{connections}{$id};
|
||||
my $tx = $c->{tx} ||= $self->_build_tx($id, $c);
|
||||
warn term_escape "-- Server <<< Client (@{[_url($tx)]})\n$chunk\n" if DEBUG;
|
||||
$tx->server_read($chunk);
|
||||
}
|
||||
|
||||
sub _remove {
|
||||
my ($self, $id) = @_;
|
||||
$self->ioloop->remove($id);
|
||||
$self->_close($id);
|
||||
}
|
||||
|
||||
sub _url { shift->req->url->to_abs }
|
||||
|
||||
sub _write {
|
||||
my ($self, $id) = @_;
|
||||
|
||||
# Protect from resume event recursion
|
||||
my $c = $self->{connections}{$id};
|
||||
return if !(my $tx = $c->{tx}) || $c->{writing};
|
||||
local $c->{writing} = 1;
|
||||
my $chunk = $tx->server_write;
|
||||
warn term_escape "-- Server >>> Client (@{[_url($tx)]})\n$chunk\n" if DEBUG;
|
||||
my $next = $tx->is_finished ? '_finish' : length $chunk ? '_write' : undef;
|
||||
return $self->ioloop->stream($id)->write($chunk) unless $next;
|
||||
weaken $self;
|
||||
$self->ioloop->stream($id)->write($chunk => sub { $self->$next($id) });
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
=encoding utf8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Mojo::Server::Daemon - Non-blocking I/O HTTP and WebSocket server
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Mojo::Server::Daemon;
|
||||
|
||||
my $daemon = Mojo::Server::Daemon->new(listen => ['http://*:8080']);
|
||||
$daemon->unsubscribe('request')->on(request => sub ($daemon, $tx) {
|
||||
|
||||
# Request
|
||||
my $method = $tx->req->method;
|
||||
my $path = $tx->req->url->path;
|
||||
|
||||
# Response
|
||||
$tx->res->code(200);
|
||||
$tx->res->headers->content_type('text/plain');
|
||||
$tx->res->body("$method request for $path!");
|
||||
|
||||
# Resume transaction
|
||||
$tx->resume;
|
||||
});
|
||||
$daemon->run;
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
L<Mojo::Server::Daemon> is a full featured, highly portable non-blocking I/O HTTP and WebSocket server, with IPv6, TLS,
|
||||
SNI, Comet (long polling), keep-alive and multiple event loop support.
|
||||
|
||||
For better scalability (epoll, kqueue) and to provide non-blocking name resolution, SOCKS5 as well as TLS support, the
|
||||
optional modules L<EV> (4.32+), L<Net::DNS::Native> (0.15+), L<IO::Socket::Socks> (0.64+) and L<IO::Socket::SSL>
|
||||
(2.009+) will be used automatically if possible. Individual features can also be disabled with the C<MOJO_NO_NNR>,
|
||||
C<MOJO_NO_SOCKS> and C<MOJO_NO_TLS> environment variables.
|
||||
|
||||
See L<Mojolicious::Guides::Cookbook/"DEPLOYMENT"> for more.
|
||||
|
||||
=head1 SIGNALS
|
||||
|
||||
The L<Mojo::Server::Daemon> process can be controlled at runtime with the following signals.
|
||||
|
||||
=head2 INT, TERM
|
||||
|
||||
Shut down server immediately.
|
||||
|
||||
=head1 EVENTS
|
||||
|
||||
L<Mojo::Server::Daemon> inherits all events from L<Mojo::Server>.
|
||||
|
||||
=head1 ATTRIBUTES
|
||||
|
||||
L<Mojo::Server::Daemon> inherits all attributes from L<Mojo::Server> and implements the following new ones.
|
||||
|
||||
=head2 acceptors
|
||||
|
||||
my $acceptors = $daemon->acceptors;
|
||||
$daemon = $daemon->acceptors(['6be0c140ef00a389c5d039536b56d139']);
|
||||
|
||||
Active acceptor ids.
|
||||
|
||||
# Check port
|
||||
mu $port = $daemon->ioloop->acceptor($daemon->acceptors->[0])->port;
|
||||
|
||||
=head2 backlog
|
||||
|
||||
my $backlog = $daemon->backlog;
|
||||
$daemon = $daemon->backlog(128);
|
||||
|
||||
Listen backlog size, defaults to C<SOMAXCONN>.
|
||||
|
||||
=head2 inactivity_timeout
|
||||
|
||||
my $timeout = $daemon->inactivity_timeout;
|
||||
$daemon = $daemon->inactivity_timeout(5);
|
||||
|
||||
Maximum amount of time in seconds a connection with an active request can be inactive before getting closed, defaults
|
||||
to the value of the C<MOJO_INACTIVITY_TIMEOUT> environment variable or C<30>. Setting the value to C<0> will allow
|
||||
connections to be inactive indefinitely.
|
||||
|
||||
=head2 ioloop
|
||||
|
||||
my $loop = $daemon->ioloop;
|
||||
$daemon = $daemon->ioloop(Mojo::IOLoop->new);
|
||||
|
||||
Event loop object to use for I/O operations, defaults to the global L<Mojo::IOLoop> singleton.
|
||||
|
||||
=head2 keep_alive_timeout
|
||||
|
||||
my $timeout = $daemon->keep_alive_timeout;
|
||||
$daemon = $daemon->keep_alive_timeout(10);
|
||||
|
||||
Maximum amount of time in seconds a connection without an active request can be inactive before getting closed,
|
||||
defaults to the value of the C<MOJO_KEEP_ALIVE_TIMEOUT> environment variable or C<5>. Setting the value to C<0> will
|
||||
allow connections to be inactive indefinitely.
|
||||
|
||||
=head2 listen
|
||||
|
||||
my $listen = $daemon->listen;
|
||||
$daemon = $daemon->listen(['https://127.0.0.1:8080']);
|
||||
|
||||
Array reference with one or more locations to listen on, defaults to the value of the C<MOJO_LISTEN> environment
|
||||
variable or C<http://*:3000> (shortcut for C<http://0.0.0.0:3000>).
|
||||
|
||||
# Listen on all IPv4 interfaces
|
||||
$daemon->listen(['http://*:3000']);
|
||||
|
||||
# Listen on all IPv4 and IPv6 interfaces
|
||||
$daemon->listen(['http://[::]:3000']);
|
||||
|
||||
# Listen on IPv6 interface
|
||||
$daemon->listen(['http://[::1]:4000']);
|
||||
|
||||
# Listen on IPv4 and IPv6 interfaces
|
||||
$daemon->listen(['http://127.0.0.1:3000', 'http://[::1]:3000']);
|
||||
|
||||
# Listen on UNIX domain socket "/tmp/myapp.sock" (percent encoded slash)
|
||||
$daemon->listen(['http+unix://%2Ftmp%2Fmyapp.sock']);
|
||||
|
||||
# File descriptor, as used by systemd
|
||||
$daemon->listen(['http://127.0.0.1?fd=3']);
|
||||
|
||||
# Allow multiple servers to use the same port (SO_REUSEPORT)
|
||||
$daemon->listen(['http://*:8080?reuse=1']);
|
||||
|
||||
# Listen on two ports with HTTP and HTTPS at the same time
|
||||
$daemon->listen(['http://*:3000', 'https://*:4000']);
|
||||
|
||||
# Use a custom certificate and key
|
||||
$daemon->listen(['https://*:3000?cert=/x/server.crt&key=/y/server.key']);
|
||||
|
||||
# Domain specific certificates and keys (SNI)
|
||||
$daemon->listen(
|
||||
['https://*:3000?example.com_cert=/x/my.crt&example.com_key=/y/my.key']);
|
||||
|
||||
# Or even a custom certificate authority
|
||||
$daemon->listen(
|
||||
['https://*:3000?cert=/x/server.crt&key=/y/server.key&ca=/z/ca.crt']);
|
||||
|
||||
These parameters are currently available:
|
||||
|
||||
=over 2
|
||||
|
||||
=item ca
|
||||
|
||||
ca=/etc/tls/ca.crt
|
||||
|
||||
Path to TLS certificate authority file used to verify the peer certificate.
|
||||
|
||||
=item cert
|
||||
|
||||
cert=/etc/tls/server.crt
|
||||
mojolicious.org_cert=/etc/tls/mojo.crt
|
||||
|
||||
Path to the TLS cert file, defaults to a built-in test certificate.
|
||||
|
||||
=item ciphers
|
||||
|
||||
ciphers=AES128-GCM-SHA256:RC4:HIGH:!MD5:!aNULL:!EDH
|
||||
|
||||
TLS cipher specification string. For more information about the format see
|
||||
L<https://www.openssl.org/docs/manmaster/man1/ciphers.html#CIPHER-STRINGS>.
|
||||
|
||||
=item fd
|
||||
|
||||
fd=3
|
||||
|
||||
File descriptor with an already prepared listen socket.
|
||||
|
||||
=item key
|
||||
|
||||
key=/etc/tls/server.key
|
||||
mojolicious.org_key=/etc/tls/mojo.key
|
||||
|
||||
Path to the TLS key file, defaults to a built-in test key.
|
||||
|
||||
=item reuse
|
||||
|
||||
reuse=1
|
||||
|
||||
Allow multiple servers to use the same port with the C<SO_REUSEPORT> socket option.
|
||||
|
||||
=item single_accept
|
||||
|
||||
single_accept=1
|
||||
|
||||
Only accept one connection at a time.
|
||||
|
||||
=item verify
|
||||
|
||||
verify=0x00
|
||||
|
||||
TLS verification mode.
|
||||
|
||||
=item version
|
||||
|
||||
version=TLSv1_2
|
||||
|
||||
TLS protocol version.
|
||||
|
||||
=back
|
||||
|
||||
=head2 max_clients
|
||||
|
||||
my $max = $daemon->max_clients;
|
||||
$daemon = $daemon->max_clients(100);
|
||||
|
||||
Maximum number of accepted connections this server is allowed to handle concurrently, before stopping to accept new
|
||||
incoming connections, passed along to L<Mojo::IOLoop/"max_connections">.
|
||||
|
||||
=head2 max_requests
|
||||
|
||||
my $max = $daemon->max_requests;
|
||||
$daemon = $daemon->max_requests(250);
|
||||
|
||||
Maximum number of keep-alive requests per connection, defaults to C<100>.
|
||||
|
||||
=head2 silent
|
||||
|
||||
my $bool = $daemon->silent;
|
||||
$daemon = $daemon->silent($bool);
|
||||
|
||||
Disable console messages.
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
L<Mojo::Server::Daemon> inherits all methods from L<Mojo::Server> and implements the following new ones.
|
||||
|
||||
=head2 ports
|
||||
|
||||
my $ports = $daemon->ports;
|
||||
|
||||
Get all ports this server is currently listening on.
|
||||
|
||||
# All ports
|
||||
say for @{$daemon->ports};
|
||||
|
||||
=head2 run
|
||||
|
||||
$daemon->run;
|
||||
|
||||
Run server and wait for L</"SIGNALS">.
|
||||
|
||||
=head2 start
|
||||
|
||||
$daemon = $daemon->start;
|
||||
|
||||
Start or resume accepting connections through L</"ioloop">.
|
||||
|
||||
# Listen on random port
|
||||
my $port = $daemon->listen(['http://127.0.0.1'])->start->ports->[0];
|
||||
|
||||
# Run multiple web servers concurrently
|
||||
my $daemon1 = Mojo::Server::Daemon->new(listen => ['http://*:3000'])->start;
|
||||
my $daemon2 = Mojo::Server::Daemon->new(listen => ['http://*:4000'])->start;
|
||||
Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
|
||||
|
||||
=head2 stop
|
||||
|
||||
$daemon = $daemon->stop;
|
||||
|
||||
Stop accepting connections through L</"ioloop">.
|
||||
|
||||
=head1 DEBUGGING
|
||||
|
||||
You can set the C<MOJO_SERVER_DEBUG> environment variable to get some advanced diagnostics information printed to
|
||||
C<STDERR>.
|
||||
|
||||
MOJO_SERVER_DEBUG=1
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Mojolicious>, L<Mojolicious::Guides>, L<https://mojolicious.org>.
|
||||
|
||||
=cut
|
||||
389
database/perl/vendor/lib/Mojo/Server/Hypnotoad.pm
vendored
Normal file
389
database/perl/vendor/lib/Mojo/Server/Hypnotoad.pm
vendored
Normal file
@@ -0,0 +1,389 @@
|
||||
package Mojo::Server::Hypnotoad;
|
||||
use Mojo::Base -base;
|
||||
|
||||
# "Bender: I was God once.
|
||||
# God: Yes, I saw. You were doing well, until everyone died."
|
||||
use Config;
|
||||
use Mojo::File qw(path);
|
||||
use Mojo::Server::Prefork;
|
||||
use Mojo::Util qw(steady_time);
|
||||
use Scalar::Util qw(weaken);
|
||||
|
||||
has prefork => sub { Mojo::Server::Prefork->new(listen => ['http://*:8080']) };
|
||||
has upgrade_timeout => 180;
|
||||
|
||||
sub configure {
|
||||
my ($self, $name) = @_;
|
||||
|
||||
# Hypnotoad settings
|
||||
my $prefork = $self->prefork;
|
||||
my $c = $prefork->app->config($name) // {};
|
||||
$self->upgrade_timeout($c->{upgrade_timeout}) if $c->{upgrade_timeout};
|
||||
|
||||
# Pre-fork settings
|
||||
$prefork->reverse_proxy($c->{proxy}) if defined $c->{proxy};
|
||||
$prefork->max_clients($c->{clients}) if $c->{clients};
|
||||
$prefork->max_requests($c->{requests}) if $c->{requests};
|
||||
defined $c->{$_} and $prefork->$_($c->{$_})
|
||||
for qw(accepts backlog graceful_timeout heartbeat_interval heartbeat_timeout inactivity_timeout keep_alive_timeout),
|
||||
qw(listen pid_file spare workers);
|
||||
}
|
||||
|
||||
sub run {
|
||||
my ($self, $app) = @_;
|
||||
|
||||
# No fork emulation support
|
||||
_exit('Hypnotoad does not support fork emulation.') if $Config{d_pseudofork};
|
||||
|
||||
# Remember executable and application for later
|
||||
$ENV{HYPNOTOAD_EXE} ||= $0;
|
||||
$0 = $ENV{HYPNOTOAD_APP} ||= path($app)->to_abs->to_string;
|
||||
|
||||
# This is a production server
|
||||
$ENV{MOJO_MODE} ||= 'production';
|
||||
|
||||
# Clean start (to make sure everything works)
|
||||
die "Can't exec: $!" if !$ENV{HYPNOTOAD_REV}++ && !exec $^X, $ENV{HYPNOTOAD_EXE};
|
||||
|
||||
# Preload application and configure server
|
||||
my $prefork = $self->prefork->cleanup(0);
|
||||
$app = $prefork->load_app($app);
|
||||
$app->config->{hypnotoad}{pid_file} //= path($ENV{HYPNOTOAD_APP})->sibling('hypnotoad.pid')->to_string;
|
||||
$self->configure('hypnotoad');
|
||||
weaken $self;
|
||||
$prefork->on(wait => sub { $self->_manage });
|
||||
$prefork->on(reap => sub { $self->_cleanup(pop) });
|
||||
$prefork->on(finish => sub { $self->_finish });
|
||||
|
||||
# Testing
|
||||
_exit('Everything looks good!') if $ENV{HYPNOTOAD_TEST};
|
||||
|
||||
# Stop running server
|
||||
$self->_stop if $ENV{HYPNOTOAD_STOP};
|
||||
|
||||
# Initiate hot deployment
|
||||
$self->_hot_deploy unless $ENV{HYPNOTOAD_PID};
|
||||
|
||||
# Daemonize as early as possible (but not for restarts)
|
||||
local $SIG{USR2} = sub { $self->{upgrade} ||= steady_time };
|
||||
$prefork->start;
|
||||
$prefork->daemonize if !$ENV{HYPNOTOAD_FOREGROUND} && $ENV{HYPNOTOAD_REV} < 3;
|
||||
|
||||
# Start accepting connections
|
||||
$prefork->cleanup(1)->run;
|
||||
}
|
||||
|
||||
sub _cleanup {
|
||||
my ($self, $pid) = @_;
|
||||
|
||||
# Clean up failed upgrade
|
||||
return unless ($self->{new} || '') eq $pid;
|
||||
$self->prefork->app->log->error('Zero downtime software upgrade failed');
|
||||
delete @$self{qw(new upgrade)};
|
||||
}
|
||||
|
||||
sub _exit { say shift and exit 0 }
|
||||
|
||||
sub _finish {
|
||||
my $self = shift;
|
||||
|
||||
$self->{finish} = 1;
|
||||
return unless my $new = $self->{new};
|
||||
|
||||
my $prefork = $self->prefork->cleanup(0);
|
||||
path($prefork->pid_file)->remove;
|
||||
$prefork->ensure_pid_file($new);
|
||||
}
|
||||
|
||||
sub _hot_deploy {
|
||||
|
||||
# Make sure server is running
|
||||
return unless my $pid = shift->prefork->check_pid;
|
||||
|
||||
# Start hot deployment
|
||||
kill 'USR2', $pid;
|
||||
_exit("Starting hot deployment for Hypnotoad server $pid.");
|
||||
}
|
||||
|
||||
sub _manage {
|
||||
my $self = shift;
|
||||
|
||||
# Upgraded (wait for all workers to send a heartbeat)
|
||||
my $prefork = $self->prefork;
|
||||
my $log = $prefork->app->log;
|
||||
if ($ENV{HYPNOTOAD_PID} && $ENV{HYPNOTOAD_PID} ne $$) {
|
||||
return unless $prefork->healthy == $prefork->workers;
|
||||
$log->info("Upgrade successful, stopping $ENV{HYPNOTOAD_PID}");
|
||||
kill 'QUIT', $ENV{HYPNOTOAD_PID};
|
||||
}
|
||||
$ENV{HYPNOTOAD_PID} = $$ unless ($ENV{HYPNOTOAD_PID} // '') eq $$;
|
||||
|
||||
# Upgrade
|
||||
if ($self->{upgrade} && !$self->{finished}) {
|
||||
|
||||
# Fresh start
|
||||
my $ut = $self->upgrade_timeout;
|
||||
unless ($self->{new}) {
|
||||
$log->info("Starting zero downtime software upgrade ($ut seconds)");
|
||||
die "Can't fork: $!" unless defined(my $pid = $self->{new} = fork);
|
||||
exec $^X, $ENV{HYPNOTOAD_EXE} or die "Can't exec: $!" unless $pid;
|
||||
}
|
||||
|
||||
# Timeout
|
||||
kill 'KILL', $self->{new} if $self->{upgrade} + $ut <= steady_time;
|
||||
}
|
||||
}
|
||||
|
||||
sub _stop {
|
||||
_exit('Hypnotoad server not running.') unless my $pid = shift->prefork->check_pid;
|
||||
kill 'QUIT', $pid;
|
||||
_exit("Stopping Hypnotoad server $pid gracefully.");
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
=encoding utf8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Mojo::Server::Hypnotoad - A production web serv...ALL GLORY TO THE HYPNOTOAD!
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Mojo::Server::Hypnotoad;
|
||||
|
||||
my $hypnotoad = Mojo::Server::Hypnotoad->new;
|
||||
$hypnotoad->run('/home/sri/myapp.pl');
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
L<Mojo::Server::Hypnotoad> is a full featured, UNIX optimized, pre-forking non-blocking I/O HTTP and WebSocket server,
|
||||
built around the very well tested and reliable L<Mojo::Server::Prefork>, with IPv6, TLS, SNI, UNIX domain socket, Comet
|
||||
(long polling), keep-alive, multiple event loop and hot deployment support that just works. Note that the server uses
|
||||
signals for process management, so you should avoid modifying signal handlers in your applications.
|
||||
|
||||
To start applications with it you can use the L<hypnotoad> script, which listens on port C<8080>, automatically
|
||||
daemonizes the server process and defaults to C<production> mode for L<Mojolicious> and L<Mojolicious::Lite>
|
||||
applications.
|
||||
|
||||
$ hypnotoad ./myapp.pl
|
||||
|
||||
You can run the same command again for automatic hot deployment.
|
||||
|
||||
$ hypnotoad ./myapp.pl
|
||||
Starting hot deployment for Hypnotoad server 31841.
|
||||
|
||||
This second invocation will load the application again, detect the process id file with it, and send a L</"USR2">
|
||||
signal to the already running server.
|
||||
|
||||
For better scalability (epoll, kqueue) and to provide non-blocking name resolution, SOCKS5 as well as TLS support, the
|
||||
optional modules L<EV> (4.32+), L<Net::DNS::Native> (0.15+), L<IO::Socket::Socks> (0.64+) and L<IO::Socket::SSL>
|
||||
(2.009+) will be used automatically if possible. Individual features can also be disabled with the C<MOJO_NO_NNR>,
|
||||
C<MOJO_NO_SOCKS> and C<MOJO_NO_TLS> environment variables.
|
||||
|
||||
See L<Mojolicious::Guides::Cookbook/"DEPLOYMENT"> for more.
|
||||
|
||||
=head1 MANAGER SIGNALS
|
||||
|
||||
The L<Mojo::Server::Hypnotoad> manager process can be controlled at runtime with the following signals.
|
||||
|
||||
=head2 INT, TERM
|
||||
|
||||
Shut down server immediately.
|
||||
|
||||
=head2 QUIT
|
||||
|
||||
Shut down server gracefully.
|
||||
|
||||
=head2 TTIN
|
||||
|
||||
Increase worker pool by one.
|
||||
|
||||
=head2 TTOU
|
||||
|
||||
Decrease worker pool by one.
|
||||
|
||||
=head2 USR2
|
||||
|
||||
Attempt zero downtime software upgrade (hot deployment) without losing any incoming connections.
|
||||
|
||||
Manager (old)
|
||||
|- Worker [1]
|
||||
|- Worker [2]
|
||||
|- Worker [3]
|
||||
|- Worker [4]
|
||||
+- Manager (new)
|
||||
|- Worker [1]
|
||||
|- Worker [2]
|
||||
|- Worker [3]
|
||||
+- Worker [4]
|
||||
|
||||
The new manager will automatically send a L</"QUIT"> signal to the old manager and take over serving requests after
|
||||
starting up successfully.
|
||||
|
||||
=head1 WORKER SIGNALS
|
||||
|
||||
L<Mojo::Server::Hypnotoad> worker processes can be controlled at runtime with the following signals.
|
||||
|
||||
=head2 QUIT
|
||||
|
||||
Stop worker gracefully.
|
||||
|
||||
=head1 SETTINGS
|
||||
|
||||
L<Mojo::Server::Hypnotoad> can be configured with the following settings, see
|
||||
L<Mojolicious::Guides::Cookbook/"Hypnotoad"> for examples.
|
||||
|
||||
=head2 accepts
|
||||
|
||||
accepts => 100
|
||||
|
||||
Maximum number of connections a worker is allowed to accept, before stopping gracefully and then getting replaced with
|
||||
a newly started worker, defaults to the value of L<Mojo::Server::Prefork/"accepts">. Setting the value to C<0> will
|
||||
allow workers to accept new connections indefinitely. Note that up to half of this value can be subtracted randomly to
|
||||
improve load balancing, and to make sure that not all workers restart at the same time.
|
||||
|
||||
=head2 backlog
|
||||
|
||||
backlog => 128
|
||||
|
||||
Listen backlog size, defaults to the value of L<Mojo::Server::Daemon/"backlog">.
|
||||
|
||||
=head2 clients
|
||||
|
||||
clients => 100
|
||||
|
||||
Maximum number of accepted connections each worker process is allowed to handle concurrently, before stopping to accept
|
||||
new incoming connections, defaults to the value of L<Mojo::IOLoop/"max_connections">. Note that high concurrency works
|
||||
best with applications that perform mostly non-blocking operations, to optimize for blocking operations you can
|
||||
decrease this value and increase L</"workers"> instead for better performance.
|
||||
|
||||
=head2 graceful_timeout
|
||||
|
||||
graceful_timeout => 15
|
||||
|
||||
Maximum amount of time in seconds stopping a worker gracefully may take before being forced, defaults to the value of
|
||||
L<Mojo::Server::Prefork/"graceful_timeout">. Note that this value should usually be a little larger than the maximum
|
||||
amount of time you expect any one request to take.
|
||||
|
||||
=head2 heartbeat_interval
|
||||
|
||||
heartbeat_interval => 3
|
||||
|
||||
Heartbeat interval in seconds, defaults to the value of L<Mojo::Server::Prefork/"heartbeat_interval">.
|
||||
|
||||
=head2 heartbeat_timeout
|
||||
|
||||
heartbeat_timeout => 2
|
||||
|
||||
Maximum amount of time in seconds before a worker without a heartbeat will be stopped gracefully, defaults to the value
|
||||
of L<Mojo::Server::Prefork/"heartbeat_timeout">. Note that this value should usually be a little larger than the
|
||||
maximum amount of time you expect any one operation to block the event loop.
|
||||
|
||||
=head2 inactivity_timeout
|
||||
|
||||
inactivity_timeout => 10
|
||||
|
||||
Maximum amount of time in seconds a connection with an active request can be inactive before getting closed, defaults
|
||||
to the value of L<Mojo::Server::Daemon/"inactivity_timeout">. Setting the value to C<0> will allow connections to be
|
||||
inactive indefinitely.
|
||||
|
||||
=head2 keep_alive_timeout
|
||||
|
||||
keep_alive_timeout => 10
|
||||
|
||||
Maximum amount of time in seconds a connection without an active request can be inactive before getting closed,
|
||||
defaults to the value of L<Mojo::Server::Daemon/"keep_alive_timeout">. Setting the value to C<0> will allow connections
|
||||
to be inactive indefinitely.
|
||||
|
||||
=head2 listen
|
||||
|
||||
listen => ['http://*:80']
|
||||
|
||||
Array reference with one or more locations to listen on, defaults to C<http://*:8080>. See also
|
||||
L<Mojo::Server::Daemon/"listen"> for more examples.
|
||||
|
||||
=head2 pid_file
|
||||
|
||||
pid_file => '/var/run/hypnotoad.pid'
|
||||
|
||||
Full path to process id file, defaults to C<hypnotoad.pid> in the same directory as the application. Note that this
|
||||
value can only be changed after the server has been stopped.
|
||||
|
||||
=head2 proxy
|
||||
|
||||
proxy => 1
|
||||
|
||||
Activate reverse proxy support, which allows for the C<X-Forwarded-For> and C<X-Forwarded-Proto> headers to be picked
|
||||
up automatically, defaults to the value of L<Mojo::Server/"reverse_proxy">.
|
||||
|
||||
=head2 requests
|
||||
|
||||
requests => 50
|
||||
|
||||
Number of keep-alive requests per connection, defaults to the value of L<Mojo::Server::Daemon/"max_requests">.
|
||||
|
||||
=head2 spare
|
||||
|
||||
spare => 4
|
||||
|
||||
Temporarily spawn up to this number of additional workers if there is a need, defaults to the value of
|
||||
L<Mojo::Server::Prefork/"spare">. This allows for new workers to be started while old ones are still shutting down
|
||||
gracefully, drastically reducing the performance cost of worker restarts.
|
||||
|
||||
=head2 upgrade_timeout
|
||||
|
||||
upgrade_timeout => 45
|
||||
|
||||
Maximum amount of time in seconds a zero downtime software upgrade may take before getting canceled, defaults to
|
||||
C<180>.
|
||||
|
||||
=head2 workers
|
||||
|
||||
workers => 10
|
||||
|
||||
Number of worker processes, defaults to the value of L<Mojo::Server::Prefork/"workers">. A good rule of thumb is two
|
||||
worker processes per CPU core for applications that perform mostly non-blocking operations, blocking operations often
|
||||
require more and benefit from decreasing concurrency with L</"clients"> (often as low as C<1>). Note that during zero
|
||||
downtime software upgrades there will be twice as many workers active for a short amount of time.
|
||||
|
||||
=head1 ATTRIBUTES
|
||||
|
||||
L<Mojo::Server::Hypnotoad> implements the following attributes.
|
||||
|
||||
=head2 prefork
|
||||
|
||||
my $prefork = $hypnotoad->prefork;
|
||||
$hypnotoad = $hypnotoad->prefork(Mojo::Server::Prefork->new);
|
||||
|
||||
L<Mojo::Server::Prefork> object this server manages.
|
||||
|
||||
=head2 upgrade_timeout
|
||||
|
||||
my $timeout = $hypnotoad->upgrade_timeout;
|
||||
$hypnotoad = $hypnotoad->upgrade_timeout(15);
|
||||
|
||||
Maximum amount of time in seconds a zero downtime software upgrade may take before getting canceled, defaults to
|
||||
C<180>.
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
L<Mojo::Server::Hypnotoad> inherits all methods from L<Mojo::Base> and implements the following new ones.
|
||||
|
||||
=head2 configure
|
||||
|
||||
$hypnotoad->configure('hypnotoad');
|
||||
|
||||
Configure server from application settings.
|
||||
|
||||
=head2 run
|
||||
|
||||
$hypnotoad->run('script/my_app');
|
||||
|
||||
Run server for application and wait for L</"MANAGER SIGNALS">.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Mojolicious>, L<Mojolicious::Guides>, L<https://mojolicious.org>.
|
||||
|
||||
=cut
|
||||
147
database/perl/vendor/lib/Mojo/Server/Morbo.pm
vendored
Normal file
147
database/perl/vendor/lib/Mojo/Server/Morbo.pm
vendored
Normal file
@@ -0,0 +1,147 @@
|
||||
package Mojo::Server::Morbo;
|
||||
use Mojo::Base -base;
|
||||
|
||||
# "Linda: With Haley's Comet out of ice, Earth is experiencing the devastating
|
||||
# effects of sudden, intense global warming.
|
||||
# Morbo: Morbo is pleased but sticky."
|
||||
use Mojo::Loader qw(load_class);
|
||||
use Mojo::Server::Daemon;
|
||||
use POSIX qw(WNOHANG);
|
||||
|
||||
has backend => sub {
|
||||
my $backend = $ENV{MOJO_MORBO_BACKEND} || 'Poll';
|
||||
$backend = "Mojo::Server::Morbo::Backend::$backend";
|
||||
return $backend->new unless my $e = load_class $backend;
|
||||
die $e if ref $e;
|
||||
die qq{Can't find Morbo backend class "$backend" in \@INC. (@INC)\n};
|
||||
};
|
||||
has daemon => sub { Mojo::Server::Daemon->new };
|
||||
|
||||
sub run {
|
||||
my ($self, $app) = @_;
|
||||
|
||||
# Clean manager environment
|
||||
local $SIG{INT} = local $SIG{TERM} = sub {
|
||||
$self->{finished} = 1;
|
||||
kill 'TERM', $self->{worker} if $self->{worker};
|
||||
};
|
||||
unshift @{$self->backend->watch}, $0 = $app;
|
||||
$self->{modified} = 1;
|
||||
|
||||
# Prepare and cache listen sockets for smooth restarting
|
||||
$self->daemon->start->stop;
|
||||
|
||||
$self->_manage until $self->{finished} && !$self->{worker};
|
||||
exit 0;
|
||||
}
|
||||
|
||||
sub _manage {
|
||||
my $self = shift;
|
||||
|
||||
if (my @files = @{$self->backend->modified_files}) {
|
||||
say @files == 1
|
||||
? qq{File "@{[$files[0]]}" changed, restarting.}
|
||||
: qq{@{[scalar @files]} files changed, restarting.}
|
||||
if $ENV{MORBO_VERBOSE};
|
||||
kill 'TERM', $self->{worker} if $self->{worker};
|
||||
$self->{modified} = 1;
|
||||
}
|
||||
|
||||
if (my $pid = $self->{worker}) {
|
||||
delete $self->{worker} if waitpid($pid, WNOHANG) == $pid;
|
||||
}
|
||||
|
||||
$self->_spawn if !$self->{worker} && delete $self->{modified};
|
||||
}
|
||||
|
||||
sub _spawn {
|
||||
my $self = shift;
|
||||
|
||||
# Manager
|
||||
my $manager = $$;
|
||||
die "Can't fork: $!" unless defined(my $pid = $self->{worker} = fork);
|
||||
return if $pid;
|
||||
|
||||
# Worker
|
||||
my $daemon = $self->daemon;
|
||||
$daemon->load_app($self->backend->watch->[0])->server($daemon);
|
||||
$daemon->ioloop->recurring(1 => sub { shift->stop unless kill 0, $manager });
|
||||
$daemon->run;
|
||||
exit 0;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
=encoding utf8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Mojo::Server::Morbo - Tonight at 11...DOOOOOOOOOOOOOOOM!
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Mojo::Server::Morbo;
|
||||
|
||||
my $morbo = Mojo::Server::Morbo->new;
|
||||
$morbo->run('/home/sri/myapp.pl');
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
L<Mojo::Server::Morbo> is a full featured, self-restart capable non-blocking I/O HTTP and WebSocket server, built
|
||||
around the very well tested and reliable L<Mojo::Server::Daemon>, with IPv6, TLS, SNI, UNIX domain socket, Comet (long
|
||||
polling), keep-alive and multiple event loop support. Note that the server uses signals for process management, so you
|
||||
should avoid modifying signal handlers in your applications.
|
||||
|
||||
To start applications with it you can use the L<morbo> script.
|
||||
|
||||
$ morbo ./myapp.pl
|
||||
Web application available at http://127.0.0.1:3000
|
||||
|
||||
For better scalability (epoll, kqueue) and to provide non-blocking name resolution, SOCKS5 as well as TLS support, the
|
||||
optional modules L<EV> (4.32+), L<Net::DNS::Native> (0.15+), L<IO::Socket::Socks> (0.64+) and L<IO::Socket::SSL>
|
||||
(2.009+) will be used automatically if possible. Individual features can also be disabled with the C<MOJO_NO_NNR>,
|
||||
C<MOJO_NO_SOCKS> and C<MOJO_NO_TLS> environment variables.
|
||||
|
||||
See L<Mojolicious::Guides::Cookbook/"DEPLOYMENT"> for more.
|
||||
|
||||
=head1 SIGNALS
|
||||
|
||||
The L<Mojo::Server::Morbo> process can be controlled at runtime with the following signals.
|
||||
|
||||
=head2 INT, TERM
|
||||
|
||||
Shut down server immediately.
|
||||
|
||||
=head1 ATTRIBUTES
|
||||
|
||||
L<Mojo::Server::Morbo> implements the following attributes.
|
||||
|
||||
=head2 backend
|
||||
|
||||
my $backend = $morbo->backend;
|
||||
$morbo = $morbo->backend(Mojo::Server::Morbo::Backend::Poll->new);
|
||||
|
||||
Backend, usually a L<Mojo::Server::Morbo::Backend::Poll> object.
|
||||
|
||||
=head2 daemon
|
||||
|
||||
my $daemon = $morbo->daemon;
|
||||
$morbo = $morbo->daemon(Mojo::Server::Daemon->new);
|
||||
|
||||
L<Mojo::Server::Daemon> object this server manages.
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
L<Mojo::Server::Morbo> inherits all methods from L<Mojo::Base> and implements the following new ones.
|
||||
|
||||
=head2 run
|
||||
|
||||
$morbo->run('script/my_app');
|
||||
|
||||
Run server for application and wait for L</"SIGNALS">.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Mojolicious>, L<Mojolicious::Guides>, L<https://mojolicious.org>.
|
||||
|
||||
=cut
|
||||
69
database/perl/vendor/lib/Mojo/Server/Morbo/Backend.pm
vendored
Normal file
69
database/perl/vendor/lib/Mojo/Server/Morbo/Backend.pm
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
package Mojo::Server::Morbo::Backend;
|
||||
use Mojo::Base -base;
|
||||
|
||||
use Carp qw(croak);
|
||||
|
||||
has watch => sub { [qw(lib templates)] };
|
||||
has watch_timeout => sub { $ENV{MOJO_MORBO_TIMEOUT} || 1 };
|
||||
|
||||
sub modified_files { croak 'Method "modified_files" not implemented by subclass' }
|
||||
|
||||
1;
|
||||
|
||||
=encoding utf8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Mojo::Server::Morbo::Backend - Morbo backend base class
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
package Mojo::Server::Morbo::Backend::Inotify:
|
||||
use Mojo::Base 'Mojo::Server::Morbo::Backend';
|
||||
|
||||
sub modified_files {...}
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
L<Mojo::Server::Morbo::Backend> is an abstract base class for Morbo backends, like
|
||||
L<Mojo::Server::Morbo::Backend::Poll>.
|
||||
|
||||
=head1 ATTRIBUTES
|
||||
|
||||
L<Mojo::Server::Morbo::Backend> implements the following attributes.
|
||||
|
||||
=head2 watch
|
||||
|
||||
my $watch = $backend->watch;
|
||||
$backend = $backend->watch(['/home/sri/my_app']);
|
||||
|
||||
Files and directories to watch for changes, defaults to the application script as well as the C<lib> and C<templates>
|
||||
directories in the current working directory.
|
||||
|
||||
=head2 watch_timeout
|
||||
|
||||
my $timeout = $backend->watch_timeout;
|
||||
$backend = $backend->watch_timeout(10);
|
||||
|
||||
Maximum amount of time in seconds a backend may block when waiting for files to change, defaults to the value of the
|
||||
C<MOJO_MORBO_TIMEOUT> environment variable or C<1>.
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
L<Mojo::Server::Morbo::Backend> inherits all methods from L<Mojo::Base> and implements the following new ones.
|
||||
|
||||
=head2 modified_files
|
||||
|
||||
my $files = $backend->modified_files;
|
||||
|
||||
Check if files from L</"watch"> have been modified since the last check and return an array reference with the results.
|
||||
Meant to be overloaded in a subclass.
|
||||
|
||||
# All files that have been modified
|
||||
say for @{$backend->modified_files};
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Mojolicious>, L<Mojolicious::Guides>, L<https://mojolicious.org>.
|
||||
|
||||
=cut
|
||||
69
database/perl/vendor/lib/Mojo/Server/Morbo/Backend/Poll.pm
vendored
Normal file
69
database/perl/vendor/lib/Mojo/Server/Morbo/Backend/Poll.pm
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
package Mojo::Server::Morbo::Backend::Poll;
|
||||
use Mojo::Base 'Mojo::Server::Morbo::Backend';
|
||||
|
||||
use Mojo::File qw(path);
|
||||
|
||||
sub modified_files {
|
||||
my $self = shift;
|
||||
|
||||
my $cache = $self->{cache} //= {};
|
||||
my @files;
|
||||
for my $file (map { -f $_ && -r _ ? $_ : _list($_) } @{$self->watch}) {
|
||||
my ($size, $mtime) = (stat $file)[7, 9];
|
||||
next unless defined $size and defined $mtime;
|
||||
my $stats = $cache->{$file} ||= [$^T, $size];
|
||||
next if $mtime <= $stats->[0] && $size == $stats->[1];
|
||||
@$stats = ($mtime, $size);
|
||||
push @files, $file;
|
||||
}
|
||||
sleep $self->watch_timeout unless @files;
|
||||
|
||||
return \@files;
|
||||
}
|
||||
|
||||
sub _list { path(shift)->list_tree->map('to_string')->each }
|
||||
|
||||
1;
|
||||
|
||||
=encoding utf8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Mojo::Server::Morbo::Backend::Poll - Morbo default backend
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Mojo::Server::Morbo::Backend::Poll;
|
||||
|
||||
my $backend = Mojo::Server::Morbo::Backend::Poll->new;
|
||||
if (my $files = $backend->modified_files) {
|
||||
...
|
||||
}
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
L<Mojo::Server::Morbo::Backend:Poll> is the default backend for L<Mojo::Server::Morbo>.
|
||||
|
||||
=head1 ATTRIBUTES
|
||||
|
||||
L<Mojo::Server::Morbo::Backend::Poll> inherits all attributes from L<Mojo::Server::Morbo::Backend>.
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
L<Mojo::Server::Morbo::Backend::Poll> inherits all methods from L<Mojo::Server::Morbo::Backend> and implements the
|
||||
following new ones.
|
||||
|
||||
=head2 modified_files
|
||||
|
||||
my $files = $backend->modified_files;
|
||||
|
||||
Check file size and mtime to determine which files have changed, this is not particularly efficient, but very portable.
|
||||
|
||||
# All files that have been modified
|
||||
say for @{$backend->modified_files};
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Mojolicious>, L<Mojolicious::Guides>, L<https://mojolicious.org>.
|
||||
|
||||
=cut
|
||||
127
database/perl/vendor/lib/Mojo/Server/PSGI.pm
vendored
Normal file
127
database/perl/vendor/lib/Mojo/Server/PSGI.pm
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
package Mojo::Server::PSGI;
|
||||
use Mojo::Base 'Mojo::Server';
|
||||
|
||||
sub run {
|
||||
my ($self, $env) = @_;
|
||||
|
||||
my $tx = $self->build_tx;
|
||||
my $req = $tx->req->parse($env);
|
||||
$tx->local_port($env->{SERVER_PORT})->remote_address($env->{REMOTE_ADDR});
|
||||
|
||||
# Request body (may block if we try to read too much)
|
||||
my $len = $env->{CONTENT_LENGTH};
|
||||
until ($req->is_finished) {
|
||||
my $chunk = ($len && $len < 131072) ? $len : 131072;
|
||||
last unless my $read = $env->{'psgi.input'}->read(my $buffer, $chunk, 0);
|
||||
$req->parse($buffer);
|
||||
last if ($len -= $read) <= 0;
|
||||
}
|
||||
|
||||
$self->emit(request => $tx);
|
||||
|
||||
# Response headers
|
||||
my $res = $tx->res->fix_headers;
|
||||
my $hash = $res->headers->to_hash(1);
|
||||
my @headers;
|
||||
for my $name (keys %$hash) { push @headers, $name, $_ for @{$hash->{$name}} }
|
||||
|
||||
# PSGI response
|
||||
my $io = Mojo::Server::PSGI::_IO->new(tx => $tx, empty => $tx->is_empty);
|
||||
return [$res->code // 404, \@headers, $io];
|
||||
}
|
||||
|
||||
sub to_psgi_app {
|
||||
my $self = shift;
|
||||
|
||||
# Preload application and wrap it
|
||||
$self->app->server($self);
|
||||
return sub { $self->run(@_) }
|
||||
}
|
||||
|
||||
package Mojo::Server::PSGI::_IO;
|
||||
use Mojo::Base -base;
|
||||
|
||||
# Finish transaction
|
||||
sub close { shift->{tx}->closed }
|
||||
|
||||
sub getline {
|
||||
my $self = shift;
|
||||
|
||||
# Empty
|
||||
return undef if $self->{empty};
|
||||
|
||||
# No content yet, try again later
|
||||
my $chunk = $self->{tx}->res->get_body_chunk($self->{offset} //= 0);
|
||||
return '' unless defined $chunk;
|
||||
|
||||
# End of content
|
||||
return undef unless length $chunk;
|
||||
|
||||
$self->{offset} += length $chunk;
|
||||
return $chunk;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
=encoding utf8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Mojo::Server::PSGI - PSGI server
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Mojo::Server::PSGI;
|
||||
|
||||
my $psgi = Mojo::Server::PSGI->new;
|
||||
$psgi->unsubscribe('request')->on(request => sub ($psgi, $tx) {
|
||||
|
||||
# Request
|
||||
my $method = $tx->req->method;
|
||||
my $path = $tx->req->url->path;
|
||||
|
||||
# Response
|
||||
$tx->res->code(200);
|
||||
$tx->res->headers->content_type('text/plain');
|
||||
$tx->res->body("$method request for $path!");
|
||||
|
||||
# Resume transaction
|
||||
$tx->resume;
|
||||
});
|
||||
my $app = $psgi->to_psgi_app;
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
L<Mojo::Server::PSGI> allows L<Mojolicious> applications to run on all L<PSGI> compatible servers.
|
||||
|
||||
See L<Mojolicious::Guides::Cookbook/"DEPLOYMENT"> for more.
|
||||
|
||||
=head1 EVENTS
|
||||
|
||||
L<Mojo::Server::PSGI> inherits all events from L<Mojo::Server>.
|
||||
|
||||
=head1 ATTRIBUTES
|
||||
|
||||
L<Mojo::Server::PSGI> inherits all attributes from L<Mojo::Server>.
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
L<Mojo::Server::PSGI> inherits all methods from L<Mojo::Server> and implements the following new ones.
|
||||
|
||||
=head2 run
|
||||
|
||||
my $res = $psgi->run($env);
|
||||
|
||||
Run L<PSGI>.
|
||||
|
||||
=head2 to_psgi_app
|
||||
|
||||
my $app = $psgi->to_psgi_app;
|
||||
|
||||
Turn L<Mojolicious> application into L<PSGI> application.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Mojolicious>, L<Mojolicious::Guides>, L<https://mojolicious.org>.
|
||||
|
||||
=cut
|
||||
412
database/perl/vendor/lib/Mojo/Server/Prefork.pm
vendored
Normal file
412
database/perl/vendor/lib/Mojo/Server/Prefork.pm
vendored
Normal file
@@ -0,0 +1,412 @@
|
||||
package Mojo::Server::Prefork;
|
||||
use Mojo::Base 'Mojo::Server::Daemon';
|
||||
|
||||
use Config;
|
||||
use File::Spec::Functions qw(tmpdir);
|
||||
use Mojo::File qw(path);
|
||||
use Mojo::Util qw(steady_time);
|
||||
use POSIX qw(WNOHANG);
|
||||
use Scalar::Util qw(weaken);
|
||||
|
||||
has accepts => 10000;
|
||||
has cleanup => 1;
|
||||
has graceful_timeout => 120;
|
||||
has heartbeat_timeout => 50;
|
||||
has heartbeat_interval => 5;
|
||||
has pid_file => sub { path(tmpdir, 'prefork.pid')->to_string };
|
||||
has spare => 2;
|
||||
has workers => 4;
|
||||
|
||||
sub DESTROY { path($_[0]->pid_file)->remove if $_[0]->cleanup }
|
||||
|
||||
sub check_pid {
|
||||
return undef unless -r (my $file = path(shift->pid_file));
|
||||
my $pid = $file->slurp;
|
||||
chomp $pid;
|
||||
|
||||
# Running
|
||||
return $pid if $pid && kill 0, $pid;
|
||||
|
||||
# Not running
|
||||
$file->remove;
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub ensure_pid_file {
|
||||
my ($self, $pid) = @_;
|
||||
|
||||
# Check if PID file already exists
|
||||
return if -e (my $file = path($self->pid_file));
|
||||
|
||||
# Create PID file
|
||||
if (my $err = eval { $file->spurt("$pid\n")->chmod(0644) } ? undef : $@) {
|
||||
$self->app->log->error(qq{Can't create process id file "$file": $err})
|
||||
and die qq{Can't create process id file "$file": $err};
|
||||
}
|
||||
$self->app->log->info(qq{Creating process id file "$file"});
|
||||
}
|
||||
|
||||
sub healthy {
|
||||
scalar grep { $_->{healthy} } values %{shift->{pool}};
|
||||
}
|
||||
|
||||
sub run {
|
||||
my $self = shift;
|
||||
|
||||
# No fork emulation support
|
||||
say 'Pre-forking does not support fork emulation.' and exit 0 if $Config{d_pseudofork};
|
||||
|
||||
# Pipe for worker communication
|
||||
pipe($self->{reader}, $self->{writer}) or die "Can't create pipe: $!";
|
||||
|
||||
# Clean manager environment
|
||||
local $SIG{CHLD} = sub {
|
||||
while ((my $pid = waitpid -1, WNOHANG) > 0) { $self->emit(reap => $pid)->_stopped($pid) }
|
||||
};
|
||||
local $SIG{INT} = local $SIG{TERM} = sub { $self->_term };
|
||||
local $SIG{QUIT} = sub { $self->_term(1) };
|
||||
local $SIG{TTIN} = sub { $self->workers($self->workers + 1) };
|
||||
local $SIG{TTOU} = sub {
|
||||
$self->workers > 0 ? $self->workers($self->workers - 1) : return;
|
||||
for my $w (values %{$self->{pool}}) { ($w->{graceful} = steady_time) and last unless $w->{graceful} }
|
||||
};
|
||||
|
||||
# Preload application before starting workers
|
||||
$self->start->app->log->info("Manager $$ started");
|
||||
$self->ioloop->max_accepts($self->accepts);
|
||||
$self->{running} = 1;
|
||||
$self->_manage while $self->{running};
|
||||
$self->app->log->info("Manager $$ stopped");
|
||||
}
|
||||
|
||||
sub _heartbeat { shift->{writer}->syswrite("$$:$_[0]\n") or exit 0 }
|
||||
|
||||
sub _manage {
|
||||
my $self = shift;
|
||||
|
||||
# Spawn more workers if necessary and check PID file
|
||||
if (!$self->{finished}) {
|
||||
my $graceful = grep { $_->{graceful} } values %{$self->{pool}};
|
||||
my $spare = $self->spare;
|
||||
$spare = $graceful ? $graceful > $spare ? $spare : $graceful : 0;
|
||||
my $need = ($self->workers - keys %{$self->{pool}}) + $spare;
|
||||
$self->_spawn while $need-- > 0;
|
||||
$self->ensure_pid_file($$);
|
||||
}
|
||||
|
||||
# Shutdown
|
||||
elsif (!keys %{$self->{pool}}) { return delete $self->{running} }
|
||||
|
||||
# Wait for heartbeats
|
||||
$self->_wait;
|
||||
|
||||
my $interval = $self->heartbeat_interval;
|
||||
my $ht = $self->heartbeat_timeout;
|
||||
my $gt = $self->graceful_timeout;
|
||||
my $log = $self->app->log;
|
||||
my $time = steady_time;
|
||||
|
||||
for my $pid (keys %{$self->{pool}}) {
|
||||
next unless my $w = $self->{pool}{$pid};
|
||||
|
||||
# No heartbeat (graceful stop)
|
||||
$log->error("Worker $pid has no heartbeat ($ht seconds), restarting") and $w->{graceful} = $time
|
||||
if !$w->{graceful} && ($w->{time} + $interval + $ht <= $time);
|
||||
|
||||
# Graceful stop with timeout
|
||||
my $graceful = $w->{graceful} ||= $self->{graceful} ? $time : undef;
|
||||
$log->info("Stopping worker $pid gracefully ($gt seconds)") and (kill 'QUIT', $pid or $self->_stopped($pid))
|
||||
if $graceful && !$w->{quit}++;
|
||||
$w->{force} = 1 if $graceful && $graceful + $gt <= $time;
|
||||
|
||||
# Normal stop
|
||||
$log->warn("Stopping worker $pid immediately") and (kill 'KILL', $pid or $self->_stopped($pid))
|
||||
if $w->{force} || ($self->{finished} && !$graceful);
|
||||
}
|
||||
}
|
||||
|
||||
sub _spawn {
|
||||
my $self = shift;
|
||||
|
||||
# Manager
|
||||
die "Can't fork: $!" unless defined(my $pid = fork);
|
||||
return $self->emit(spawn => $pid)->{pool}{$pid} = {time => steady_time} if $pid;
|
||||
|
||||
# Heartbeat messages
|
||||
my $loop = $self->cleanup(0)->ioloop;
|
||||
my $finished = 0;
|
||||
$loop->on(finish => sub { $finished = 1 });
|
||||
weaken $self;
|
||||
my $cb = sub { $self->_heartbeat($finished) };
|
||||
$loop->next_tick($cb);
|
||||
$loop->recurring($self->heartbeat_interval => $cb);
|
||||
|
||||
# Clean worker environment
|
||||
$SIG{$_} = 'DEFAULT' for qw(CHLD INT TERM TTIN TTOU);
|
||||
$SIG{QUIT} = sub { $loop->stop_gracefully };
|
||||
$loop->on(finish => sub { $self->max_requests(1) });
|
||||
delete $self->{reader};
|
||||
srand;
|
||||
|
||||
$self->app->log->info("Worker $$ started");
|
||||
$loop->start;
|
||||
exit 0;
|
||||
}
|
||||
|
||||
sub _stopped {
|
||||
my ($self, $pid) = @_;
|
||||
|
||||
return unless my $w = delete $self->{pool}{$pid};
|
||||
|
||||
my $log = $self->app->log;
|
||||
$log->info("Worker $pid stopped");
|
||||
$log->error("Worker $pid stopped too early, shutting down") and $self->_term unless $w->{healthy};
|
||||
}
|
||||
|
||||
sub _term {
|
||||
my ($self, $graceful) = @_;
|
||||
@{$self->emit(finish => $graceful)}{qw(finished graceful)} = (1, $graceful);
|
||||
}
|
||||
|
||||
sub _wait {
|
||||
my $self = shift;
|
||||
|
||||
# Poll for heartbeats
|
||||
my $reader = $self->emit('wait')->{reader};
|
||||
return unless Mojo::Util::_readable(1000, fileno($reader));
|
||||
return unless $reader->sysread(my $chunk, 4194304);
|
||||
|
||||
# Update heartbeats (and stop gracefully if necessary)
|
||||
my $time = steady_time;
|
||||
while ($chunk =~ /(\d+):(\d)\n/g) {
|
||||
next unless my $w = $self->{pool}{$1};
|
||||
@$w{qw(healthy time)} = (1, $time) and $self->emit(heartbeat => $1);
|
||||
$w->{graceful} ||= $time if $2;
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
=encoding utf8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Mojo::Server::Prefork - Pre-forking non-blocking I/O HTTP and WebSocket server
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Mojo::Server::Prefork;
|
||||
|
||||
my $prefork = Mojo::Server::Prefork->new(listen => ['http://*:8080']);
|
||||
$prefork->unsubscribe('request')->on(request => sub ($prefork, $tx) {
|
||||
|
||||
# Request
|
||||
my $method = $tx->req->method;
|
||||
my $path = $tx->req->url->path;
|
||||
|
||||
# Response
|
||||
$tx->res->code(200);
|
||||
$tx->res->headers->content_type('text/plain');
|
||||
$tx->res->body("$method request for $path!");
|
||||
|
||||
# Resume transaction
|
||||
$tx->resume;
|
||||
});
|
||||
$prefork->run;
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
L<Mojo::Server::Prefork> is a full featured, UNIX optimized, pre-forking non-blocking I/O HTTP and WebSocket server,
|
||||
built around the very well tested and reliable L<Mojo::Server::Daemon>, with IPv6, TLS, SNI, UNIX domain socket, Comet
|
||||
(long polling), keep-alive and multiple event loop support. Note that the server uses signals for process management,
|
||||
so you should avoid modifying signal handlers in your applications.
|
||||
|
||||
For better scalability (epoll, kqueue) and to provide non-blocking name resolution, SOCKS5 as well as TLS support, the
|
||||
optional modules L<EV> (4.32+), L<Net::DNS::Native> (0.15+), L<IO::Socket::Socks> (0.64+) and L<IO::Socket::SSL>
|
||||
(1.84+) will be used automatically if possible. Individual features can also be disabled with the C<MOJO_NO_NNR>,
|
||||
C<MOJO_NO_SOCKS> and C<MOJO_NO_TLS> environment variables.
|
||||
|
||||
See L<Mojolicious::Guides::Cookbook/"DEPLOYMENT"> for more.
|
||||
|
||||
=head1 MANAGER SIGNALS
|
||||
|
||||
The L<Mojo::Server::Prefork> manager process can be controlled at runtime with the following signals.
|
||||
|
||||
=head2 INT, TERM
|
||||
|
||||
Shut down server immediately.
|
||||
|
||||
=head2 QUIT
|
||||
|
||||
Shut down server gracefully.
|
||||
|
||||
=head2 TTIN
|
||||
|
||||
Increase worker pool by one.
|
||||
|
||||
=head2 TTOU
|
||||
|
||||
Decrease worker pool by one.
|
||||
|
||||
=head1 WORKER SIGNALS
|
||||
|
||||
L<Mojo::Server::Prefork> worker processes can be controlled at runtime with the following signals.
|
||||
|
||||
=head2 QUIT
|
||||
|
||||
Stop worker gracefully.
|
||||
|
||||
=head1 EVENTS
|
||||
|
||||
L<Mojo::Server::Prefork> inherits all events from L<Mojo::Server::Daemon> and can emit the following new ones.
|
||||
|
||||
=head2 finish
|
||||
|
||||
$prefork->on(finish => sub ($prefork, $graceful) {...});
|
||||
|
||||
Emitted when the server shuts down.
|
||||
|
||||
$prefork->on(finish => sub ($prefork, $graceful) {
|
||||
say $graceful ? 'Graceful server shutdown' : 'Server shutdown';
|
||||
});
|
||||
|
||||
=head2 heartbeat
|
||||
|
||||
$prefork->on(heartbeat => sub ($prefork, $pid) {...});
|
||||
|
||||
Emitted when a heartbeat message has been received from a worker.
|
||||
|
||||
$prefork->on(heartbeat => sub ($prefork, $pid) { say "Worker $pid has a heartbeat" });
|
||||
|
||||
=head2 reap
|
||||
|
||||
$prefork->on(reap => sub ($prefork, $pid) {...});
|
||||
|
||||
Emitted when a child process exited.
|
||||
|
||||
$prefork->on(reap => sub ($prefork, $pid) { say "Worker $pid stopped" });
|
||||
|
||||
=head2 spawn
|
||||
|
||||
$prefork->on(spawn => sub ($prefork, $pid) {...});
|
||||
|
||||
Emitted when a worker process is spawned.
|
||||
|
||||
$prefork->on(spawn => sub ($prefork, $pid) { say "Worker $pid started" });
|
||||
|
||||
=head2 wait
|
||||
|
||||
$prefork->on(wait => sub ($prefork) {...});
|
||||
|
||||
Emitted when the manager starts waiting for new heartbeat messages.
|
||||
|
||||
$prefork->on(wait => sub ($prefork) {
|
||||
my $workers = $prefork->workers;
|
||||
say "Waiting for heartbeat messages from $workers workers";
|
||||
});
|
||||
|
||||
=head1 ATTRIBUTES
|
||||
|
||||
L<Mojo::Server::Prefork> inherits all attributes from L<Mojo::Server::Daemon> and implements the following new ones.
|
||||
|
||||
=head2 accepts
|
||||
|
||||
my $accepts = $prefork->accepts;
|
||||
$prefork = $prefork->accepts(100);
|
||||
|
||||
Maximum number of connections a worker is allowed to accept, before stopping gracefully and then getting replaced with
|
||||
a newly started worker, passed along to L<Mojo::IOLoop/"max_accepts">, defaults to C<10000>. Setting the value to C<0>
|
||||
will allow workers to accept new connections indefinitely. Note that up to half of this value can be subtracted
|
||||
randomly to improve load balancing, and to make sure that not all workers restart at the same time.
|
||||
|
||||
=head2 cleanup
|
||||
|
||||
my $bool = $prefork->cleanup;
|
||||
$prefork = $prefork->cleanup($bool);
|
||||
|
||||
Delete L</"pid_file"> automatically once it is not needed anymore, defaults to a true value.
|
||||
|
||||
=head2 graceful_timeout
|
||||
|
||||
my $timeout = $prefork->graceful_timeout;
|
||||
$prefork = $prefork->graceful_timeout(15);
|
||||
|
||||
Maximum amount of time in seconds stopping a worker gracefully may take before being forced, defaults to C<120>. Note
|
||||
that this value should usually be a little larger than the maximum amount of time you expect any one request to take.
|
||||
|
||||
=head2 heartbeat_interval
|
||||
|
||||
my $interval = $prefork->heartbeat_interval;
|
||||
$prefork = $prefork->heartbeat_interval(3);
|
||||
|
||||
Heartbeat interval in seconds, defaults to C<5>.
|
||||
|
||||
=head2 heartbeat_timeout
|
||||
|
||||
my $timeout = $prefork->heartbeat_timeout;
|
||||
$prefork = $prefork->heartbeat_timeout(2);
|
||||
|
||||
Maximum amount of time in seconds before a worker without a heartbeat will be stopped gracefully, defaults to C<50>.
|
||||
Note that this value should usually be a little larger than the maximum amount of time you expect any one operation to
|
||||
block the event loop.
|
||||
|
||||
=head2 pid_file
|
||||
|
||||
my $file = $prefork->pid_file;
|
||||
$prefork = $prefork->pid_file('/tmp/prefork.pid');
|
||||
|
||||
Full path of process id file, defaults to C<prefork.pid> in a temporary directory.
|
||||
|
||||
=head2 spare
|
||||
|
||||
my $spare = $prefork->spare;
|
||||
$prefork = $prefork->spare(4);
|
||||
|
||||
Temporarily spawn up to this number of additional workers if there is a need, defaults to C<2>. This allows for new
|
||||
workers to be started while old ones are still shutting down gracefully, drastically reducing the performance cost of
|
||||
worker restarts.
|
||||
|
||||
=head2 workers
|
||||
|
||||
my $workers = $prefork->workers;
|
||||
$prefork = $prefork->workers(10);
|
||||
|
||||
Number of worker processes, defaults to C<4>. A good rule of thumb is two worker processes per CPU core for
|
||||
applications that perform mostly non-blocking operations, blocking operations often require more and benefit from
|
||||
decreasing concurrency with L<Mojo::Server::Daemon/"max_clients"> (often as low as C<1>).
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
L<Mojo::Server::Prefork> inherits all methods from L<Mojo::Server::Daemon> and implements the following new ones.
|
||||
|
||||
=head2 check_pid
|
||||
|
||||
my $pid = $prefork->check_pid;
|
||||
|
||||
Get process id for running server from L</"pid_file"> or delete it if server is not running.
|
||||
|
||||
say 'Server is not running' unless $prefork->check_pid;
|
||||
|
||||
=head2 ensure_pid_file
|
||||
|
||||
$prefork->ensure_pid_file($pid);
|
||||
|
||||
Ensure L</"pid_file"> exists.
|
||||
|
||||
=head2 healthy
|
||||
|
||||
my $healthy = $prefork->healthy;
|
||||
|
||||
Number of currently active worker processes with a heartbeat.
|
||||
|
||||
=head2 run
|
||||
|
||||
$prefork->run;
|
||||
|
||||
Run server and wait for L</"MANAGER SIGNALS">.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Mojolicious>, L<Mojolicious::Guides>, L<https://mojolicious.org>.
|
||||
|
||||
=cut
|
||||
Reference in New Issue
Block a user