|
package Mojolicious::Command::router; |
|
use Mojo::Base 'Mojolicious::Command'; |
|
|
|
use Mojo::Log; |
|
use Mojo::UserAgent; |
|
use Mojo::Server::Prefork; |
|
use Mojo::File 'path'; |
|
use Mojo::Util qw'dumper getopt'; |
|
use Mojo::Collection 'c'; |
|
use Mojo::ByteStream 'b'; |
|
|
|
use Mojoxy; |
|
|
|
has description => |
|
'Start application with pre-forking HTTP and WebSocket server'; |
|
has usage => sub { shift->extract_usage }; |
|
|
|
sub run { |
|
my ($self, @args) = @_; |
|
my $redirects; |
|
my $server = Mojo::Server::Prefork->new(app => Mojoxy->new); |
|
getopt \@args, |
|
'a|accepts=i' => sub { $server->accepts($_[1]) }, |
|
'b|backlog=i' => sub { $server->backlog($_[1]) }, |
|
'c|clients=i' => sub { $server->max_clients($_[1]) }, |
|
'G|graceful-timeout=i' => sub { $server->graceful_timeout($_[1]) }, |
|
'I|heartbeat-interval=i' => sub { $server->heartbeat_interval($_[1]) }, |
|
'H|heartbeat-timeout=i' => sub { $server->heartbeat_timeout($_[1]) }, |
|
'i|inactivity-timeout=i' => sub { $server->inactivity_timeout($_[1]) }, |
|
'l|listen=s' => \my @listen, |
|
'P|pid-file=s' => sub { $server->pid_file($_[1]) }, |
|
'p|proxy' => sub { $server->reverse_proxy(1) }, |
|
'r|requests=i' => sub { $server->max_requests($_[1]) }, |
|
's|spare=i' => sub { $server->spare($_[1]) }, |
|
'w|workers=i' => sub { $server->workers($_[1]) }, |
|
'L|log=s' => \$ENV{MOJOXY_LOG}, |
|
'r|redirects=s' => sub { $redirects = c(b(path($_)->slurp)->split("\n")) }, |
|
's|status=s' => \(my $status = 404), |
|
'S|sockets=s' => \$ENV{MOJOXY_SOCKETS}; |
|
|
|
my $log = Mojo::Log->new; |
|
$log->path($ENV{MOJOXY_LOG}) |
|
if $ENV{MOJOXY_LOG} && (-f $ENV{MOJOXY_LOG} && -w _ || -d path($ENV{MOJOXY_LOG})->dirname && -w _); |
|
$ENV{MOJOXY_SOCKETS} && -d $ENV{MOJOXY_SOCKETS} |
|
or die "Usage: $0 -S /path/to/socketdir\n"; |
|
|
|
my $ua = Mojo::UserAgent->new; |
|
$server->listen(\@listen) if @listen; |
|
$server->unsubscribe('request')->on(request => sub { |
|
my ($server, $tx) = @_; |
|
|
|
# Setup the request |
|
my $req = $tx->req->clone; |
|
my $host = $req->headers->host; |
|
|
|
return $server->app->handler($tx) if $host eq 'proxy'; |
|
|
|
# Determine which socket to use |
|
my $socket = path($ENV{MOJOXY_SOCKETS}); |
|
my @host = split /\./, ($req->headers->host || 'default'); |
|
$socket = $socket->child($_) foreach reverse @host; |
|
$socket = $socket->child('.root') if -e $socket->to_abs && -d _; |
|
$log->error(sprintf '%s (%s) [no app at %s]', $host, $status, $socket->to_abs) and return abort($tx, $status) |
|
unless -e $socket->to_abs && -S _; |
|
|
|
# app socket exists and so the app should be running and accessible |
|
# A client receiving an EMPTY 404 probably indicates that the app is not running |
|
# An app MUST remove sockets upon removal / uninstallation |
|
$req->url->scheme('http+unix')->host($socket->to_abs); |
|
$ua->start(Mojo::Transaction::HTTP->new(req => $req) => sub { |
|
my ($ua, $proxy_tx) = @_; |
|
my $level = 'debug'; |
|
my $message = ''; |
|
unless ( $proxy_tx->res->code ) { |
|
$level = 'error'; |
|
$proxy_tx->res->code(502); |
|
$message = sprintf 'app probably not running at %s', $socket->to_abs; |
|
} |
|
$log->$level(sprintf '%s (%s) [%s]', $host, $proxy_tx->res->code, $message); |
|
$tx->res($proxy_tx->res)->resume; |
|
}); |
|
}); |
|
$server->run; |
|
} |
|
|
|
sub abort { |
|
my ($tx, $code) = @_; |
|
$tx->res->code($code) if $code; |
|
$tx->resume; |
|
} |
|
|
|
1; |
|
|
|
=encoding utf8 |
|
|
|
=head1 NAME |
|
|
|
Mojolicious::Command::prefork - Pre-fork command |
|
|
|
=head1 SYNOPSIS |
|
|
|
Usage: APPLICATION prefork [OPTIONS] |
|
|
|
./myapp.pl prefork |
|
./myapp.pl prefork -m production -l http://*:8080 |
|
./myapp.pl prefork -l http://127.0.0.1:8080 -l https://[::]:8081 |
|
./myapp.pl prefork -l 'https://*:443?cert=./server.crt&key=./server.key' |
|
./myapp.pl prefork -l http+unix://%2Ftmp%2Fmyapp.sock -w 12 |
|
|
|
Options: |
|
-a, --accepts <number> Number of connections for workers to |
|
accept, defaults to 10000 |
|
-b, --backlog <size> Listen backlog size, defaults to |
|
SOMAXCONN |
|
-c, --clients <number> Maximum number of concurrent |
|
connections, defaults to 1000 |
|
-G, --graceful-timeout <seconds> Graceful timeout, defaults to 120. |
|
-I, --heartbeat-interval <seconds> Heartbeat interval, defaults to 5 |
|
-H, --heartbeat-timeout <seconds> Heartbeat timeout, defaults to 30 |
|
-h, --help Show this summary of available options |
|
--home <path> Path to home directory of your |
|
application, defaults to the value of |
|
MOJO_HOME or auto-detection |
|
-i, --inactivity-timeout <seconds> Inactivity timeout, defaults to the |
|
value of MOJO_INACTIVITY_TIMEOUT or 15 |
|
-l, --listen <location> One or more locations you want to |
|
listen on, defaults to the value of |
|
MOJO_LISTEN or "http://*:3000" |
|
-m, --mode <name> Operating mode for your application, |
|
defaults to the value of |
|
MOJO_MODE/PLACK_ENV or "development" |
|
-P, --pid-file <path> Path to process id file, defaults to |
|
"prefork.pid" in a temporary directory |
|
-p, --proxy Activate reverse proxy support, |
|
defaults to the value of |
|
MOJO_REVERSE_PROXY |
|
-r, --requests <number> Maximum number of requests per |
|
keep-alive connection, defaults to 100 |
|
-s, --spare <number> Temporarily spawn up to this number of |
|
additional workers, defaults to 2 |
|
-w, --workers <number> Number of workers, defaults to 4 |
|
|
|
=head1 DESCRIPTION |
|
|
|
L<Mojolicious::Command::prefork> starts applications with the |
|
L<Mojo::Server::Prefork> backend. |
|
|
|
This is a core command, that means it is always enabled and its code a good |
|
example for learning to build new commands, you're welcome to fork it. |
|
|
|
See L<Mojolicious::Commands/"COMMANDS"> for a list of commands that are |
|
available by default. |
|
|
|
=head1 ATTRIBUTES |
|
|
|
L<Mojolicious::Command::prefork> inherits all attributes from |
|
L<Mojolicious::Command> and implements the following new ones. |
|
|
|
=head2 description |
|
|
|
my $description = $prefork->description; |
|
$prefork = $prefork->description('Foo'); |
|
|
|
Short description of this command, used for the command list. |
|
|
|
=head2 usage |
|
|
|
my $usage = $prefork->usage; |
|
$prefork = $prefork->usage('Foo'); |
|
|
|
Usage information for this command, used for the help screen. |
|
|
|
=head1 METHODS |
|
|
|
L<Mojolicious::Command::prefork> inherits all methods from |
|
L<Mojolicious::Command> and implements the following new ones. |
|
|
|
=head2 run |
|
|
|
$prefork->run(@ARGV); |
|
|
|
Run this command. |
|
|
|
=head1 SEE ALSO |
|
|
|
L<Mojolicious>, L<Mojolicious::Guides>, L<https://mojolicious.org>. |
|
|
|
=cut |