Subject: | 'shutdown' on one default-arg Client-Keepalive makes all future default-arg Client-Keepalive unusable |
To reproduce:
- create a POE::Component::Client::Keepalive using the `new' method,
with no arguments.
- use it.
- later, shut it down by the `shutdown' method.
- create another POE::Component::Client::Keepalive using the `new'
method, with no arguments.
- attempt to use it.
- observe that it dies with "resolve() on shutdown resolver"
Demonstrated by an attached patch which adds t/14_resolver_shutdown.t
autotest.
Tested with c846f073d727aca73c2a1048a88568278b5cca1b from
http://gitorious.org/poe-component-client-keepalive
One simple fix is also attached.
I hit this bug indirectly by using POE::Component::Client::HTTP.
Symptoms are similar, shutting down one PoCo-Client-HTTP will make any
newly created PoCo-Client-HTTP attempt to use a resolver which has been
shut down.
Subject: | 0001-Added-autotest-for-resolver-shutdown-bug.patch |
From 14d70663099715f5f0c13a950ee4d3f4d38f9b41 Mon Sep 17 00:00:00 2001
From: Rohan McGovern <rohan@mcgovern.id.au>
Date: Sat, 16 Jul 2011 14:39:22 +1000
Subject: [PATCH 1/2] Added autotest for resolver shutdown bug.
---
t/14_resolver_shutdown.t | 79 ++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 79 insertions(+), 0 deletions(-)
create mode 100644 t/14_resolver_shutdown.t
diff --git a/t/14_resolver_shutdown.t b/t/14_resolver_shutdown.t
new file mode 100644
index 0000000..33d4ce6
--- /dev/null
+++ b/t/14_resolver_shutdown.t
@@ -0,0 +1,79 @@
+#!/usr/bin/perl
+
+use warnings;
+use strict;
+use lib qw(./mylib ../mylib);
+use Test::More tests => 2;
+
+use POE;
+use POE::Component::Client::Keepalive;
+
+use TestServer;
+
+# Random port. Kludge until TestServer can report a port number.
+use constant PORT => int(rand(65535-2000)) + 2000;
+TestServer->spawn(PORT);
+
+POE::Session->create(
+ inline_states => {
+ _child => sub { },
+ _start => \&start,
+ _stop => sub { },
+ got_conn1 => \&got_conn1,
+ got_conn2 => \&got_conn2,
+ }
+);
+
+sub start {
+ my ($kernel, $heap) = @_[KERNEL, HEAP];
+
+ $kernel->alias_set('SHUTDOWN-TEST');
+
+ $heap->{cm} = POE::Component::Client::Keepalive->new();
+
+ $heap->{cm}->allocate(
+ scheme => "http",
+ addr => "localhost",
+ port => PORT,
+ event => "got_conn1",
+ context => "first",
+ );
+}
+
+sub got_conn1 {
+ my $heap = $_[HEAP];
+
+ pass("got_conn1 called");
+
+ $heap->{cm}->shutdown;
+
+ # The BUG being tested here is that, after shutting down
+ # a Keepalive with a default resolver, any newly created Keepalive
+ # will fail, because it will attempt to reuse the same default
+ # resolver (which has been shut down, so it croaks).
+ #
+ # If got_conn2 is called, the bug is not present.
+
+ $heap->{cm} = POE::Component::Client::Keepalive->new();
+
+ $heap->{cm}->allocate(
+ scheme => "http",
+ addr => "localhost",
+ port => PORT,
+ event => "got_conn2",
+ context => "first",
+ );
+}
+
+sub got_conn2 {
+ my $heap = $_[HEAP];
+
+ pass("got_conn2 called");
+
+ $heap->{cm}->shutdown;
+ delete $heap->{cm};
+ TestServer->shutdown();
+}
+
+POE::Kernel->run();
+exit;
--
1.7.0.4
Subject: | 0002-Prevent-shutdown-leaving-behind-a-broken-default_res.patch |
From 3266de3c45442cd2a4990582d1fa7650df89c73e Mon Sep 17 00:00:00 2001
From: Rohan McGovern <rohan@mcgovern.id.au>
Date: Sat, 16 Jul 2011 14:35:20 +1000
Subject: [PATCH 2/2] Prevent `shutdown' leaving behind a broken $default_resolver
Shutting down the component would also shutdown the resolver which was
used, even if this was the $default_resolver. This is wrong since the
$default_resolver may be used by other instances of this class, or
instances created in the future.
Fixes RT#????
---
lib/POE/Component/Client/Keepalive.pm | 9 ++++++---
1 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/lib/POE/Component/Client/Keepalive.pm b/lib/POE/Component/Client/Keepalive.pm
index c49e6c0..9e16abf 100644
--- a/lib/POE/Component/Client/Keepalive.pm
+++ b/lib/POE/Component/Client/Keepalive.pm
@@ -830,9 +830,12 @@ sub _ka_shutdown {
}
$heap->{resolve} = { };
- # Shut down the resolver.
- DEBUG and warn "SHT: Shutting down resolver";
- $self->[SF_RESOLVER]->shutdown();
+ # Shut down the resolver
+ # (but not the default resolver, which may be used by other instances)
+ if ($self->[SF_RESOLVER] != $default_resolver) {
+ DEBUG and warn "SHT: Shutting down resolver";
+ $self->[SF_RESOLVER]->shutdown();
+ }
$self->[SF_RESOLVER] = undef;
# Finish keepalive's shutdown.
--
1.7.0.4