1 | package Mojo::Server::Morbo;
|
---|
2 | use Mojo::Base -base;
|
---|
3 |
|
---|
4 | # "Linda: With Haley's Comet out of ice, Earth is experiencing the devastating
|
---|
5 | # effects of sudden, intense global warming.
|
---|
6 | # Morbo: Morbo is pleased but sticky."
|
---|
7 | use Mojo::Loader 'load_class';
|
---|
8 | use Mojo::Server::Daemon;
|
---|
9 | use POSIX 'WNOHANG';
|
---|
10 |
|
---|
11 | has backend => sub {
|
---|
12 | my $backend = $ENV{MOJO_MORBO_BACKEND} || 'Poll';
|
---|
13 | $backend = "Mojo::Server::Morbo::Backend::$backend";
|
---|
14 | return $backend->new unless my $e = load_class $backend;
|
---|
15 | die $e if ref $e;
|
---|
16 | die qq{Can't find Morbo backend class "$backend" in \@INC. (@INC)\n};
|
---|
17 | };
|
---|
18 | has daemon => sub { Mojo::Server::Daemon->new };
|
---|
19 |
|
---|
20 | sub run {
|
---|
21 | my ($self, $app) = @_;
|
---|
22 |
|
---|
23 | # Clean manager environment
|
---|
24 | local $SIG{INT} = local $SIG{TERM} = sub {
|
---|
25 | $self->{finished} = 1;
|
---|
26 | kill 'TERM', $self->{worker} if $self->{worker};
|
---|
27 | };
|
---|
28 | unshift @{$self->backend->watch}, $0 = $app;
|
---|
29 | $self->{modified} = 1;
|
---|
30 |
|
---|
31 | # Prepare and cache listen sockets for smooth restarting
|
---|
32 | $self->daemon->start->stop;
|
---|
33 |
|
---|
34 | $self->_manage until $self->{finished} && !$self->{worker};
|
---|
35 | exit 0;
|
---|
36 | }
|
---|
37 |
|
---|
38 | sub _manage {
|
---|
39 | my $self = shift;
|
---|
40 |
|
---|
41 | if (my @files = @{$self->backend->modified_files}) {
|
---|
42 | say @files == 1
|
---|
43 | ? qq{File "@{[$files[0]]}" changed, restarting.}
|
---|
44 | : qq{@{[scalar @files]} files changed, restarting.}
|
---|
45 | if $ENV{MORBO_VERBOSE};
|
---|
46 | kill 'TERM', $self->{worker} if $self->{worker};
|
---|
47 | $self->{modified} = 1;
|
---|
48 | }
|
---|
49 |
|
---|
50 | if (my $pid = $self->{worker}) {
|
---|
51 | delete $self->{worker} if waitpid($pid, WNOHANG) == $pid;
|
---|
52 | }
|
---|
53 |
|
---|
54 | $self->_spawn if !$self->{worker} && delete $self->{modified};
|
---|
55 | }
|
---|
56 |
|
---|
57 | sub _spawn {
|
---|
58 | my $self = shift;
|
---|
59 |
|
---|
60 | # Manager
|
---|
61 | my $manager = $$;
|
---|
62 | die "Can't fork: $!" unless defined(my $pid = $self->{worker} = fork);
|
---|
63 | return if $pid;
|
---|
64 |
|
---|
65 | # Worker
|
---|
66 | my $daemon = $self->daemon;
|
---|
67 | $daemon->load_app($self->backend->watch->[0]);
|
---|
68 | $daemon->ioloop->recurring(1 => sub { shift->stop unless kill 0, $manager });
|
---|
69 | $daemon->run;
|
---|
70 | exit 0;
|
---|
71 | }
|
---|
72 |
|
---|
73 | 1;
|
---|
74 |
|
---|
75 | =encoding utf8
|
---|
76 |
|
---|
77 | =head1 NAME
|
---|
78 |
|
---|
79 | Mojo::Server::Morbo - Tonight at 11...DOOOOOOOOOOOOOOOM!
|
---|
80 |
|
---|
81 | =head1 SYNOPSIS
|
---|
82 |
|
---|
83 | use Mojo::Server::Morbo;
|
---|
84 |
|
---|
85 | my $morbo = Mojo::Server::Morbo->new;
|
---|
86 | $morbo->run('/home/sri/myapp.pl');
|
---|
87 |
|
---|
88 | =head1 DESCRIPTION
|
---|
89 |
|
---|
90 | L<Mojo::Server::Morbo> is a full featured, self-restart capable non-blocking
|
---|
91 | I/O HTTP and WebSocket server, built around the very well tested and reliable
|
---|
92 | L<Mojo::Server::Daemon>, with IPv6, TLS, SNI, UNIX domain socket, Comet (long
|
---|
93 | polling), keep-alive and multiple event loop support. Note that the server uses
|
---|
94 | signals for process management, so you should avoid modifying signal handlers in
|
---|
95 | your applications.
|
---|
96 |
|
---|
97 | To start applications with it you can use the L<morbo> script.
|
---|
98 |
|
---|
99 | $ morbo ./myapp.pl
|
---|
100 | Server available at http://127.0.0.1:3000
|
---|
101 |
|
---|
102 | For better scalability (epoll, kqueue) and to provide non-blocking name
|
---|
103 | resolution, SOCKS5 as well as TLS support, the optional modules L<EV> (4.0+),
|
---|
104 | L<Net::DNS::Native> (0.15+), L<IO::Socket::Socks> (0.64+) and
|
---|
105 | L<IO::Socket::SSL> (2.009+) will be used automatically if possible. Individual
|
---|
106 | features can also be disabled with the C<MOJO_NO_NNR>, C<MOJO_NO_SOCKS> and
|
---|
107 | C<MOJO_NO_TLS> environment variables.
|
---|
108 |
|
---|
109 | See L<Mojolicious::Guides::Cookbook/"DEPLOYMENT"> for more.
|
---|
110 |
|
---|
111 | =head1 SIGNALS
|
---|
112 |
|
---|
113 | The L<Mojo::Server::Morbo> process can be controlled at runtime with the
|
---|
114 | following signals.
|
---|
115 |
|
---|
116 | =head2 INT, TERM
|
---|
117 |
|
---|
118 | Shut down server immediately.
|
---|
119 |
|
---|
120 | =head1 ATTRIBUTES
|
---|
121 |
|
---|
122 | L<Mojo::Server::Morbo> implements the following attributes.
|
---|
123 |
|
---|
124 | =head2 backend
|
---|
125 |
|
---|
126 | my $backend = $morbo->backend;
|
---|
127 | $morbo = $morbo->backend(Mojo::Server::Morbo::Backend::Poll->new);
|
---|
128 |
|
---|
129 | Backend, usually a L<Mojo::Server::Morbo::Backend::Poll> object.
|
---|
130 |
|
---|
131 | =head2 daemon
|
---|
132 |
|
---|
133 | my $daemon = $morbo->daemon;
|
---|
134 | $morbo = $morbo->daemon(Mojo::Server::Daemon->new);
|
---|
135 |
|
---|
136 | L<Mojo::Server::Daemon> object this server manages.
|
---|
137 |
|
---|
138 | =head1 METHODS
|
---|
139 |
|
---|
140 | L<Mojo::Server::Morbo> inherits all methods from L<Mojo::Base> and implements
|
---|
141 | the following new ones.
|
---|
142 |
|
---|
143 | =head2 run
|
---|
144 |
|
---|
145 | $morbo->run('script/my_app');
|
---|
146 |
|
---|
147 | Run server for application and wait for L</"SIGNALS">.
|
---|
148 |
|
---|
149 | =head1 SEE ALSO
|
---|
150 |
|
---|
151 | L<Mojolicious>, L<Mojolicious::Guides>, L<https://mojolicious.org>.
|
---|
152 |
|
---|
153 | =cut
|
---|