I have an application that runs as a stand-alone daemon returning SOAP
results. It's been running fine for a long time, but I recently noticed
the memory growing and not being released after every connection.

I've created a custom module based on the code of
SOAP::Transport::HTTP::Daemon, but supporting spawning threads when a
connection is accepted.

Running ActivePerl 5.8.8.822 with threads 1.6.3 and threads::shared 1.12
under CentOS Linux.

Here's a sample application that can be used to reproduce the problem.

SOAPServer.pl:
--------------
#!perl

use strict;
use threads ('stack_size' => 32*4096, 'exit' => 'threads_only');
use SOAPDaemon;

sub Start {
        my $SOAPServerThread = threads->new(sub {
                my $SOAPServer = SOAPDaemon->new(
                        LocalPort       => 10000,
                        ReuseAddr       => 1
                )->dispatch_to('main');
                
                $SOAPServer->Handle;
        });
}

sub Ping {
        my $Self = shift;
        
        return {Valid => 1, Output => 'Pong'};
}

Start();

while(1) {
        sleep(1);
}

SOAPDaemon.pm:
--------------
#!perl
package SOAPDaemon;

# Custom package derived from SOAP::Transport::HTTP::Daemon

use Data::Dumper;
use Carp ();
use HTTP::Daemon;
use SOAP::Transport::HTTP;

use vars qw($AUTOLOAD @ISA);
@ISA = qw(SOAP::Transport::HTTP::Server);

sub DESTROY { SOAP::Trace::objects('()') }

sub new {
        my $self = shift;
        
        unless (ref $self) {
                my $class = ref($self) || $self;
                
                my(@params, @methods);
                while (@_) { $class->can($_[0]) ? push(@methods, shift()
=> shift) : push(@params, shift) }
                $self = $class->SUPER::new;
                
                $self->{_daemon} = HTTP::Daemon->new(@params) or
Carp::croak "Can't create daemon: $!";
                
        
$self->myuri(URI->new($self->url)->canonical->as_string);
                while (@methods) {
                        my($method, $params) = splice(@methods,0,2);
                        $self->$method(ref $params eq 'ARRAY' ? @$params
: $params) 
                }
                SOAP::Trace::objects('()');
        }
        
        return $self;
}

sub AUTOLOAD {
        my $method = substr($AUTOLOAD, rindex($AUTOLOAD, '::') + 2);
        return if $method eq 'DESTROY';
        
        no strict 'refs';
        *$AUTOLOAD = sub { shift->{_daemon}->$method(@_) };
        goto &$AUTOLOAD;
}

sub Handle {
        my $self = shift->new;
        
        while (my $c = $self->accept) {
                threads->new(\&SOAPWorker, $self, $c);
        }
}

sub SOAPWorker {
        my $Obj = shift;
        my $c   = shift;
        
        while (my $r = $c->get_request(0)) {
                $Obj->request($r);
                $Obj->SUPER::handle;
                $c->send_response($Obj->response);
        }
        
        # replaced ->close, thanks to Sean Meisner
<[EMAIL PROTECTED]>
        # shutdown() doesn't work on AIX. close() is used in this case.
Thanks to Jos Clijmans <[EMAIL PROTECTED]>
        UNIVERSAL::isa($c, 'shutdown') ? $c->shutdown(2) : $c->close(); 
        $c->close;
        
        threads->self()->detach();
}

# Always end package with true
1;

__END__

Reply via email to