Permalink
Browse files

Keep sidecar processes around longer, and provide an idle_timeout con…

…structor parameter to override just how long that is. This is a partial response to Karen_m's report of PID and memory churn introduced by lots of forking.
  • Loading branch information...
1 parent 1acb470 commit faa1588e8a7417b20c3745490e50033bcc744f54 @rcaputo committed Apr 24, 2011
Showing with 52 additions and 17 deletions.
  1. +48 −17 lib/POE/Component/Resolver.pm
  2. +4 −0 t/01-basic.t
@@ -26,6 +26,7 @@ sub new {
my %args = @args;
my $max_resolvers = delete($args{max_resolvers}) || 8;
+ my $idle_timeout = delete($args{idle_timeout}) || 15;
my $af_order = delete($args{af_order});
if (defined $af_order and @$af_order) {
@@ -65,7 +66,15 @@ sub new {
sidecar_eject => \&_poe_sidecar_eject,
sidecar_attach => \&_poe_sidecar_attach,
},
- args => [ "$self", $max_resolvers, $af_order ],
+ heap => {
+ af_order => $af_order,
+ alias => "$self",
+ idle_timeout => $idle_timeout,
+ last_request_id => 0,
+ max_resolvers => $max_resolvers,
+ requests => { },
+ sidecar_ring => [ ],
+ }
);
return $self;
@@ -142,25 +151,19 @@ sub _poe_request {
sidecar_id => $next_sidecar->ID(),
};
+ # No ejecting until we're done.
+ $kernel->delay(sidecar_eject => undef);
+
return 1;
}
# POE _start handler. Initialize the session and start sidecar
# processes, which are owned and managed by that session.
sub _poe_start {
- my ($kernel, $heap, $alias, $max_resolvers, $af_order) = @_[
- KERNEL, HEAP, ARG0..ARG2
- ];
-
- $heap->{af_order} = $af_order;
- $heap->{requests} = {};
- $heap->{last_reuqest_id} = 0;
- $heap->{alias} = $alias;
- $heap->{max_resolvers} = $max_resolvers;
- $heap->{sidecar_ring} = [];
+ my ($kernel, $heap) = @_[KERNEL, HEAP];
- $kernel->alias_set($alias);
+ $kernel->alias_set($heap->{alias});
_poe_setup_sidecar_ring($kernel, $heap);
@@ -175,7 +178,7 @@ sub _poe_setup_sidecar_ring {
return if $heap->{shutdown};
- while (scalar keys %{$heap->{sidecar}} < $heap->{max_resolvers}) {
+ while (scalar(keys %{$heap->{sidecar}}) < $heap->{max_resolvers}) {
my $sidecar = POE::Wheel::Run->new(
StdioFilter => POE::Filter::Reference->new(),
StdoutEvent => 'sidecar_response',
@@ -373,7 +376,9 @@ sub _poe_sidecar_response {
$kernel->refcount_decrement($request_rec->{sender}, __PACKAGE__);
# No more requests? Consder detaching sidecar.
- $kernel->yield("sidecar_eject") unless scalar keys %{$heap->{requests}};
+ $kernel->delay(sidecar_eject => $heap->{idle_timeout}) unless (
+ scalar keys %{$heap->{requests}}
+ );
}
# A sidecar process has exited. Clean up its resources, and attach a
@@ -456,7 +461,8 @@ POE::Component::Resolver - A non-blocking getaddrinfo() resolver
my $r = POE::Component::Resolver->new(
max_resolvers => 8,
- af_order => [ AF_INET6, AF_INET ],
+ idle_timeout => 5,
+ af_order => [ AF_INET6, AF_INET ],
);
my @hosts = qw( ipv6-test.com );
@@ -526,10 +532,13 @@ Socket::GetAddrInfo provides them.
af_order => [ AF_INET6 ]
);
+"idle_timeout" determines how long to keep idle resolver subprocesses
+before cleaning them up, in seconds. It defaults to 15.0 seconds.
+
"max_resolvers" controls the component's parallelism by defining the
maximum number of sidecar processes to manage. It defaults to 8, but
-fewer or more processes can be configured depending on usage
-requirements.
+fewer or more processes can be configured depending on the resources
+you have available and the amount of parallelism you require.
# One at a time, but without the pesky blocking.
my $r3 = POE::Component::Resolver->new( max_resolvers => 1 );
@@ -649,6 +658,28 @@ There is no timeout on requests.
There is no way to cancel a pending request.
+=head1 TROUBLESHOOTING
+
+=head2 programs linger for several seconds before exiting
+
+Programs should destroy their POE::Component::Resolver objects when
+they are through needing asynchronous DNS resolution.
+
+In some cases, it may be necessary to shutdown components that perform
+asynchronous DNS using POE::Component::Resolver... such as
+POE::Component::IRC, POE::Component::Client::Keepalive and
+POE::Component::Client::HTTP.
+
+By default, the resolver subprocesses hang around for idle_timeout,
+which defaults to 15.0 seconds. Destroying the Resolver object will
+clean up the process pool. Assuming only that is keeping the event
+loop active, the program will then exit cleanly.
+
+Alternatively, reduce idle_timeout to a more manageable number, such
+as 5.0 seconds.
+
+Otherwise something else may also be keeping the event loop active.
+
=head1 LICENSE
Except where otherwise noted, this distribution is Copyright 2011 by
View
@@ -11,6 +11,7 @@ use POE::Component::Resolver qw(AF_INET AF_INET6);
my $r4 = POE::Component::Resolver->new(
max_resolvers => 1,
+ idle_timeout => 1,
af_order => [ AF_INET ],
);
@@ -30,16 +31,19 @@ my ($r6, $r46, $r64);
if ($has_ipv6) {
$r6 = POE::Component::Resolver->new(
max_resolvers => 1,
+ idle_timeout => 1,
af_order => [ AF_INET6 ],
);
$r46 = POE::Component::Resolver->new(
max_resolvers => 1,
+ idle_timeout => 1,
af_order => [ AF_INET, AF_INET6 ],
);
$r64 = POE::Component::Resolver->new(
max_resolvers => 1,
+ idle_timeout => 1,
af_order => [ AF_INET6, AF_INET ],
);
}

0 comments on commit faa1588

Please sign in to comment.