File Coverage

blib/lib/Mojo/Server/Hypnotoad.pm
Criterion Covered Total %
statement 18 84 21.4
branch 0 48 0.0
condition 0 37 0.0
subroutine 6 18 33.3
pod 2 2 100.0
total 26 189 13.7


line stmt bran cond sub pod time code
1             package Mojo::Server::Hypnotoad;
2 1     1   569 use Mojo::Base -base;
  1         2  
  1         10  
3              
4             # "Bender: I was God once.
5             # God: Yes, I saw. You were doing well, until everyone died."
6 1     1   7 use Config;
  1         2  
  1         36  
7 1     1   5 use Mojo::File qw(path);
  1         8  
  1         44  
8 1     1   569 use Mojo::Server::Prefork;
  1         4  
  1         9  
9 1     1   7 use Mojo::Util qw(steady_time);
  1         2  
  1         55  
10 1     1   5 use Scalar::Util qw(weaken);
  1         3  
  1         1522  
11              
12             has prefork => sub { Mojo::Server::Prefork->new(listen => ['http://*:8080']) };
13             has upgrade_timeout => 180;
14              
15             sub configure {
16 0     0 1   my ($self, $name) = @_;
17              
18             # Hypnotoad settings
19 0           my $prefork = $self->prefork;
20 0   0       my $c = $prefork->app->config($name) // {};
21 0 0         $self->upgrade_timeout($c->{upgrade_timeout}) if $c->{upgrade_timeout};
22              
23             # Pre-fork settings
24 0 0         $prefork->reverse_proxy($c->{proxy}) if defined $c->{proxy};
25 0 0         $prefork->trusted_proxies($c->{trusted_proxies}) if defined $c->{trusted_proxies};
26 0 0         $prefork->max_clients($c->{clients}) if $c->{clients};
27 0 0         $prefork->max_requests($c->{requests}) if $c->{requests};
28             defined $c->{$_} and $prefork->$_($c->{$_})
29 0   0       for qw(accepts backlog graceful_timeout heartbeat_interval heartbeat_timeout inactivity_timeout keep_alive_timeout),
30             qw(listen pid_file spare workers);
31             }
32              
33             sub run {
34 0     0 1   my ($self, $app) = @_;
35              
36             # No fork emulation support
37 0 0         _exit('Hypnotoad does not support fork emulation.') if $Config{d_pseudofork};
38              
39             # Remember executable and application for later
40 0   0       $ENV{HYPNOTOAD_EXE} ||= $0;
41 0   0       $0 = $ENV{HYPNOTOAD_APP} ||= path($app)->to_abs->to_string;
42              
43             # This is a production server
44 0   0       $ENV{MOJO_MODE} ||= 'production';
45              
46             # Clean start (to make sure everything works)
47 0 0 0       die "Can't exec: $!" if !$ENV{HYPNOTOAD_REV}++ && !exec $^X, $ENV{HYPNOTOAD_EXE};
48              
49             # Preload application and configure server
50 0           my $prefork = $self->prefork->cleanup(0);
51 0           $app = $prefork->load_app($app);
52 0   0       $app->config->{hypnotoad}{pid_file} //= path($ENV{HYPNOTOAD_APP})->sibling('hypnotoad.pid')->to_string;
53 0           $self->configure('hypnotoad');
54 0           weaken $self;
55 0     0     $prefork->on(wait => sub { $self->_manage });
  0            
56 0     0     $prefork->on(reap => sub { $self->_cleanup(pop) });
  0            
57 0     0     $prefork->on(finish => sub { $self->_finish });
  0            
58              
59             # Testing
60 0 0         _exit('Everything looks good!') if $ENV{HYPNOTOAD_TEST};
61              
62             # Stop running server
63 0 0         $self->_stop if $ENV{HYPNOTOAD_STOP};
64              
65             # Initiate hot deployment
66 0 0         $self->_hot_deploy unless $ENV{HYPNOTOAD_PID};
67              
68             # Daemonize as early as possible (but not for restarts)
69 0   0 0     local $SIG{USR2} = sub { $self->{upgrade} ||= steady_time };
  0            
70 0           $prefork->start;
71 0 0 0       $prefork->daemonize if !$ENV{HYPNOTOAD_FOREGROUND} && $ENV{HYPNOTOAD_REV} < 3;
72              
73             # Start accepting connections
74 0           $prefork->cleanup(1)->run;
75             }
76              
77             sub _cleanup {
78 0     0     my ($self, $pid) = @_;
79              
80             # Clean up failed upgrade
81 0 0 0       return unless ($self->{new} || '') eq $pid;
82 0           $self->prefork->app->log->error('Zero downtime software upgrade failed');
83 0           delete @$self{qw(new upgrade)};
84             }
85              
86 0 0   0     sub _exit { say shift and exit 0 }
87              
88             sub _finish {
89 0     0     my $self = shift;
90              
91 0           $self->{finish} = 1;
92 0 0         return unless my $new = $self->{new};
93              
94 0           my $prefork = $self->prefork->cleanup(0);
95 0           path($prefork->pid_file)->remove;
96 0           $prefork->ensure_pid_file($new);
97             }
98              
99             sub _hot_deploy {
100              
101             # Make sure server is running
102 0 0   0     return unless my $pid = shift->prefork->check_pid;
103              
104             # Start hot deployment
105 0           kill 'USR2', $pid;
106 0           _exit("Starting hot deployment for Hypnotoad server $pid.");
107             }
108              
109             sub _manage {
110 0     0     my $self = shift;
111              
112             # Upgraded (wait for all workers to send a heartbeat)
113 0           my $prefork = $self->prefork;
114 0           my $log = $prefork->app->log;
115 0 0 0       if ($ENV{HYPNOTOAD_PID} && $ENV{HYPNOTOAD_PID} ne $$) {
116 0 0         return unless $prefork->healthy == $prefork->workers;
117 0           $log->info("Upgrade successful, stopping $ENV{HYPNOTOAD_PID}");
118 0           kill 'QUIT', $ENV{HYPNOTOAD_PID};
119             }
120 0 0 0       $ENV{HYPNOTOAD_PID} = $$ unless ($ENV{HYPNOTOAD_PID} // '') eq $$;
121              
122             # Upgrade
123 0 0 0       if ($self->{upgrade} && !$self->{finished}) {
124              
125             # Fresh start
126 0           my $ut = $self->upgrade_timeout;
127 0 0         unless ($self->{new}) {
128 0           $log->info("Starting zero downtime software upgrade ($ut seconds)");
129 0 0         die "Can't fork: $!" unless defined(my $pid = $self->{new} = fork);
130 0 0 0       exec $^X, $ENV{HYPNOTOAD_EXE} or die "Can't exec: $!" unless $pid;
131             }
132              
133             # Timeout
134 0 0         kill 'KILL', $self->{new} if $self->{upgrade} + $ut <= steady_time;
135             }
136             }
137              
138             sub _stop {
139 0 0   0     _exit('Hypnotoad server not running.') unless my $pid = shift->prefork->check_pid;
140 0           kill 'QUIT', $pid;
141 0           _exit("Stopping Hypnotoad server $pid gracefully.");
142             }
143              
144             1;
145              
146             =encoding utf8
147              
148             =head1 NAME
149              
150             Mojo::Server::Hypnotoad - A production web serv...ALL GLORY TO THE HYPNOTOAD!
151              
152             =head1 SYNOPSIS
153              
154             use Mojo::Server::Hypnotoad;
155              
156             my $hypnotoad = Mojo::Server::Hypnotoad->new;
157             $hypnotoad->run('/home/sri/myapp.pl');
158              
159             =head1 DESCRIPTION
160              
161             L is a full featured, UNIX optimized, pre-forking non-blocking I/O HTTP and WebSocket server,
162             built around the very well tested and reliable L, with IPv6, TLS, SNI, UNIX domain socket, Comet
163             (long polling), keep-alive, multiple event loop and hot deployment support that just works. Note that the server uses
164             signals for process management, so you should avoid modifying signal handlers in your applications.
165              
166             To start applications with it you can use the L script, which listens on port C<8080>, automatically
167             daemonizes the server process and defaults to C mode for L and L
168             applications.
169              
170             $ hypnotoad ./myapp.pl
171              
172             You can run the same command again for automatic hot deployment.
173              
174             $ hypnotoad ./myapp.pl
175             Starting hot deployment for Hypnotoad server 31841.
176              
177             This second invocation will load the application again, detect the process id file with it, and send a L
178             signal to the already running server.
179              
180             For better scalability (epoll, kqueue) and to provide non-blocking name resolution, SOCKS5 as well as TLS support, the
181             optional modules L (4.32+), L (0.15+), L (0.64+) and L
182             (2.009+) will be used automatically if possible. Individual features can also be disabled with the C,
183             C and C environment variables.
184              
185             See L for more.
186              
187             =head1 MANAGER SIGNALS
188              
189             The L manager process can be controlled at runtime with the following signals.
190              
191             =head2 INT, TERM
192              
193             Shut down server immediately.
194              
195             =head2 QUIT
196              
197             Shut down server gracefully.
198              
199             =head2 TTIN
200              
201             Increase worker pool by one.
202              
203             =head2 TTOU
204              
205             Decrease worker pool by one.
206              
207             =head2 USR2
208              
209             Attempt zero downtime software upgrade (hot deployment) without losing any incoming connections.
210              
211             Manager (old)
212             |- Worker [1]
213             |- Worker [2]
214             |- Worker [3]
215             |- Worker [4]
216             +- Manager (new)
217             |- Worker [1]
218             |- Worker [2]
219             |- Worker [3]
220             +- Worker [4]
221              
222             The new manager will automatically send a L signal to the old manager and take over serving requests after
223             starting up successfully.
224              
225             =head1 WORKER SIGNALS
226              
227             L worker processes can be controlled at runtime with the following signals.
228              
229             =head2 QUIT
230              
231             Stop worker gracefully.
232              
233             =head1 SETTINGS
234              
235             L can be configured with the following settings, see
236             L for examples.
237              
238             =head2 accepts
239              
240             accepts => 100
241              
242             Maximum number of connections a worker is allowed to accept, before stopping gracefully and then getting replaced with
243             a newly started worker, defaults to the value of L. Setting the value to C<0> will
244             allow workers to accept new connections indefinitely. Note that up to half of this value can be subtracted randomly to
245             improve load balancing, and to make sure that not all workers restart at the same time.
246              
247             =head2 backlog
248              
249             backlog => 128
250              
251             Listen backlog size, defaults to the value of L.
252              
253             =head2 clients
254              
255             clients => 100
256              
257             Maximum number of accepted connections each worker process is allowed to handle concurrently, before stopping to accept
258             new incoming connections, defaults to the value of L. Note that high concurrency works
259             best with applications that perform mostly non-blocking operations, to optimize for blocking operations you can
260             decrease this value and increase L instead for better performance.
261              
262             =head2 graceful_timeout
263              
264             graceful_timeout => 15
265              
266             Maximum amount of time in seconds stopping a worker gracefully may take before being forced, defaults to the value of
267             L. Note that this value should usually be a little larger than the maximum
268             amount of time you expect any one request to take.
269              
270             =head2 heartbeat_interval
271              
272             heartbeat_interval => 3
273              
274             Heartbeat interval in seconds, defaults to the value of L.
275              
276             =head2 heartbeat_timeout
277              
278             heartbeat_timeout => 2
279              
280             Maximum amount of time in seconds before a worker without a heartbeat will be stopped gracefully, defaults to the value
281             of L. Note that this value should usually be a little larger than the
282             maximum amount of time you expect any one operation to block the event loop.
283              
284             =head2 inactivity_timeout
285              
286             inactivity_timeout => 10
287              
288             Maximum amount of time in seconds a connection with an active request can be inactive before getting closed, defaults
289             to the value of L. Setting the value to C<0> will allow connections to be
290             inactive indefinitely.
291              
292             =head2 keep_alive_timeout
293              
294             keep_alive_timeout => 10
295              
296             Maximum amount of time in seconds a connection without an active request can be inactive before getting closed,
297             defaults to the value of L. Setting the value to C<0> will allow connections
298             to be inactive indefinitely.
299              
300             =head2 listen
301              
302             listen => ['http://*:80']
303              
304             Array reference with one or more locations to listen on, defaults to C. See also
305             L for more examples.
306              
307             =head2 pid_file
308              
309             pid_file => '/var/run/hypnotoad.pid'
310              
311             Full path to process id file, defaults to C in the same directory as the application. Note that this
312             value can only be changed after the server has been stopped.
313              
314             =head2 proxy
315              
316             proxy => 1
317              
318             Activate reverse proxy support, which allows for the C and C headers to be picked
319             up automatically, defaults to the value of L.
320              
321             =head2 requests
322              
323             requests => 50
324              
325             Number of keep-alive requests per connection, defaults to the value of L.
326              
327             =head2 spare
328              
329             spare => 4
330              
331             Temporarily spawn up to this number of additional workers if there is a need, defaults to the value of
332             L. This allows for new workers to be started while old ones are still shutting down
333             gracefully, drastically reducing the performance cost of worker restarts.
334              
335             =head2 trusted_proxies
336              
337             trusted_proxies => ['10.0.0.0/8', '127.0.0.1', '172.16.0.0/12', '192.168.0.0/16', 'fc00::/7']
338              
339             Trusted reverse proxies, addresses or networks in CIDR form.
340              
341             =head2 upgrade_timeout
342              
343             upgrade_timeout => 45
344              
345             Maximum amount of time in seconds a zero downtime software upgrade may take before getting canceled, defaults to
346             C<180>.
347              
348             =head2 workers
349              
350             workers => 10
351              
352             Number of worker processes, defaults to the value of L. A good rule of thumb is two
353             worker processes per CPU core for applications that perform mostly non-blocking operations, blocking operations often
354             require more and benefit from decreasing concurrency with L (often as low as C<1>). Note that during zero
355             downtime software upgrades there will be twice as many workers active for a short amount of time.
356              
357             =head1 ATTRIBUTES
358              
359             L implements the following attributes.
360              
361             =head2 prefork
362              
363             my $prefork = $hypnotoad->prefork;
364             $hypnotoad = $hypnotoad->prefork(Mojo::Server::Prefork->new);
365              
366             L object this server manages.
367              
368             =head2 upgrade_timeout
369              
370             my $timeout = $hypnotoad->upgrade_timeout;
371             $hypnotoad = $hypnotoad->upgrade_timeout(15);
372              
373             Maximum amount of time in seconds a zero downtime software upgrade may take before getting canceled, defaults to
374             C<180>.
375              
376             =head1 METHODS
377              
378             L inherits all methods from L and implements the following new ones.
379              
380             =head2 configure
381              
382             $hypnotoad->configure('hypnotoad');
383              
384             Configure server from application settings.
385              
386             =head2 run
387              
388             $hypnotoad->run('script/my_app');
389              
390             Run server for application and wait for L.
391              
392             =head1 SEE ALSO
393              
394             L, L, L.
395              
396             =cut