Skip to content

Commit

Permalink
improved Mojo::UserAgent connection management to be fork-safe
Browse files Browse the repository at this point in the history
  • Loading branch information
kraih committed Jul 27, 2013
1 parent ffdc824 commit 4b38124
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 9 deletions.
3 changes: 2 additions & 1 deletion Changes
@@ -1,5 +1,6 @@

4.20 2013-07-25
4.20 2013-07-27
- Improved Mojo::UserAgent connection management to be fork-safe.

4.19 2013-07-21
- Improved invalid tag handling in Mojo::DOM::HTML.
Expand Down
12 changes: 6 additions & 6 deletions lib/Mojo/IOLoop.pm
Expand Up @@ -305,18 +305,18 @@ L<Mojo::IOLoop> is a very minimalistic event loop based on L<Mojo::Reactor>,
it has been reduced to the absolute minimal feature set required to build
solid and scalable non-blocking TCP clients and servers.
For better scalability (epoll, kqueue) and to provide IPv6 as well as TLS
support, the optional modules L<EV> (4.0+), L<IO::Socket::IP> (0.16+) and
L<IO::Socket::SSL> (1.75+) will be used automatically if they are installed.
Individual features can also be disabled with the MOJO_NO_IPV6 and MOJO_NO_TLS
environment variables.
The event loop will be resilient to time jumps if a monotonic clock is
available through L<Time::HiRes>. A TLS certificate and key are also built
right in, to make writing test servers as easy as possible. Also note that for
convenience the C<PIPE> signal will be set to C<IGNORE> when L<Mojo::IOLoop>
is loaded.
For better scalability (epoll, kqueue) and to provide IPv6 as well as TLS
support, the optional modules L<EV> (4.0+), L<IO::Socket::IP> (0.16+) and
L<IO::Socket::SSL> (1.75+) will be used automatically if they are installed.
Individual features can also be disabled with the MOJO_NO_IPV6 and MOJO_NO_TLS
environment variables.
See L<Mojolicious::Guides::Cookbook> for more.
=head1 ATTRIBUTES
Expand Down
8 changes: 8 additions & 0 deletions lib/Mojo/UserAgent.pm
Expand Up @@ -77,6 +77,12 @@ sub need_proxy {
sub start {
my ($self, $tx, $cb) = @_;

# Fork safety
unless (($self->{pid} //= $$) eq $$) {
$self->_cleanup;
delete $self->{$_} for qw(pid port);
}

# Non-blocking
if ($cb) {
warn "-- Non-blocking request (@{[$tx->req->url->to_abs]})\n" if DEBUG;
Expand Down Expand Up @@ -560,6 +566,8 @@ agent, with IPv6, TLS, SNI, IDNA, Comet (long polling), keep-alive, connection
pooling, timeout, cookie, multipart, proxy, gzip compression and multiple
event loop support.
All connections will be reset automatically if a new process has been forked.
For better scalability (epoll, kqueue) and to provide IPv6 as well as TLS
support, the optional modules L<EV> (4.0+), L<IO::Socket::IP> (0.16+) and
L<IO::Socket::SSL> (1.75+) will be used automatically by L<Mojo::IOLoop> if
Expand Down
27 changes: 25 additions & 2 deletions t/mojo/user_agent.t
Expand Up @@ -327,6 +327,29 @@ ok !$tx->success, 'not successful';
is(($tx->error)[0], 'Not Found', 'right error');
is(($tx->error)[1], 404, 'right status');

# Fork safety
$tx = $ua->get('/');
is $tx->res->body, 'works!', 'right content';
my $last = $tx->connection;
my $port = $ua->app_url->port;
$tx = $ua->get('/');
is $tx->res->body, 'works!', 'right content';
is $tx->connection, $last, 'same connection';
is $ua->app_url->port, $port, 'same port';
{
local $$ = -23;
$tx = $ua->get('/');
is $tx->res->body, 'works!', 'right content';
isnt $tx->connection, $last, 'new connection';
isnt $ua->app_url->port, $port, 'new port';
$port = $ua->app_url->port;
$last = $tx->connection;
$tx = $ua->get('/');
is $tx->res->body, 'works!', 'right content';
is $tx->connection, $last, 'same connection';
is $ua->app_url->port, $port, 'same port';
}

# Introspect
my $req = my $res = '';
my $start = $ua->on(
Expand Down Expand Up @@ -452,8 +475,8 @@ is $tx->res->code, 200, 'right status';
is $tx->res->body, 'works!', 'right content';

# Unexpected 1xx responses
my $port = Mojo::IOLoop->generate_port;
$req = Mojo::Message::Request->new;
$port = Mojo::IOLoop->generate_port;
$req = Mojo::Message::Request->new;
Mojo::IOLoop->server(
{address => '127.0.0.1', port => $port} => sub {
my ($loop, $stream) = @_;
Expand Down

0 comments on commit 4b38124

Please sign in to comment.