Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked

My daemon will not restart

by graq (Curate)
on Feb 14, 2008 at 15:38 UTC ( #667943=perlquestion: print w/replies, xml ) Need Help??

graq has asked for the wisdom of the Perl Monks concerning the following question:

Esteemed monks!

I am running a small TCP daemon that needs to be able to kick-start itself from a client connection. I.e. it is possible for the client to send data that should cause the whole script to restart itself.

I have scavenged around, and grabbed code from some of the nodes down these branches: 131572 and 529604. From those I have managed to replicate my same original problem.

The server

#!/usr/bin/perl use strict; use warnings; use Net::EasyTCP; use constant LOG_DIR => '/tmp'; use constant LOG_FILE => 'daemon.log'; use constant PIDDIR => LOG_DIR; use Proc::PID_File; use Proc::Daemon; use Log::Dispatch; use Log::Dispatch::File; use Date::Format; use File::Spec; sub dienice ($); our $ME = $0; $ME =~ s|.*/||; our $PIDFILE = PIDDIR."/$"; startDaemon(); our $HOSTNAME = `hostname`; chomp $HOSTNAME; my $log = new Log::Dispatch( callbacks => sub { my %h=@_; return Date::Format::time2str('%B %e %T', time)." ".$HOSTN +AME." $0\[$$]: ".$h{message}."\n"; } ); $log->add( Log::Dispatch::File->new( name => 'file1', min_level => 'warning', mode => 'append', filename => File::Spec->catfile(LOG_DIR, LOG_FILE), ) ); $log->warning("Starting Processing: ".time() ); my $daemon_path = $0; my $perl_path; open(SOURCE, $daemon_path); <SOURCE> =~ /^#!(\S+)/; $perl_path = $1; close(SOURCE); if (!-x $perl_path) { $perl_path = $^X; } my @daemon_argv = @ARGV; my $server; $server = Net::EasyTCP->new( mode => "server", port => 12345, ) || die "ERROR CREATING SERVER: $@\n"; $server->setcallback( data => \&gotdata, connect => \&connected, disconnect => \&disconnected ) || die "ERROR SETTING CALLBACKS: $@\n"; $log->warning('Server starting...'); $server->start() || die "ERROR STARTING SERVER: $@\n"; $log->warning('Server has stopped - we need to restart!'); &restart_daemon; #--------------------------------------------------------------------- +--------- # sub gotdata #--------------------------------------------------------------------- +--------- sub gotdata { my $client = shift; my $serial = $client->serial(); my $data = $client->data(); $log->warning( "Client sent data: $data" ); if( $data eq "HUP" ){ $server->stop(); $log->warning( 'Server sent HUP by client!' ); } } #--------------------------------------------------------------------- +--------- # sub connected #--------------------------------------------------------------------- +--------- sub connected { my $client = shift; my $serial = $client->serial(); $log->warning( "Client $serial just connected." ); } #--------------------------------------------------------------------- +--------- # sub disconnected #--------------------------------------------------------------------- +--------- sub disconnected { my $client = shift; my $serial = $client->serial(); $log->warning( "Client $serial just disconnected." ); } #--------------------------------------------------------------------- +--------- # sub restart_daemon #--------------------------------------------------------------------- +--------- sub restart_daemon { $log->warning( "RESTART: $perl_path, $daemon_path, @daemon_argv" ); release_the_pid_file(); exec($perl_path, $daemon_path, @daemon_argv) || $log->warning("EXEC +failed: $! $? $@"); die "Failed to restart daemon"; } #--------------------------------------------------------------------- +--------- # sub restart_daemon #--------------------------------------------------------------------- +--------- sub startDaemon { eval { Proc::Daemon::Init; }; dienice("Unable to start daemon: $@") if $@; dienice("Already running!") if hold_pid_file($PIDFILE); } #--------------------------------------------------------------------- +--------- # sub dienice #--------------------------------------------------------------------- +--------- sub dienice ($) { my ($package, $filename, $line) = caller; $log->critical("$_[0] at line $line in $filename"); die $_[0]; } __END__

And the 'hupping' client

#!/usr/bin/perl use strict; use warnings; use Net::EasyTCP; my $host = $ARGV[0] || 'localhost'; my %client = ( mode => "client", host => $host, port => 12345, ); my $client = Net::EasyTCP->new(%client) || die "ERROR CREATING CLIENT: + $@\n"; $client->send('HUP') || die "ERROR SENDING: $@\n"; print "HUP Done\n"; sleep 3; my $client2 = Net::EasyTCP->new(%client) || die "ERROR CREATING CLIENT +2: $@\n"; $client2->send('TEST') || die "ERROR SENDING: $@\n"; print "OK..\n"; my $reply = $client2->receive() || die "ERROR RECEIVING: $@\n"; print "reply: $reply\n"; $client->close(); __END__

Something somewhere is stopping this from restarting itself, and I cannot, for whatever reason, see it:

>perl HUP Done ERROR CREATING CLIENT2: Could not connect to localhost:12345: Connecti +on refused

Server output:

February 14 15:26:21 localhost[32293]: Starting Process +ing: 1203002781 February 14 15:26:21 localhost[32293]: Server starting. +.. February 14 15:32:43 localhost[32293]: Client 1 just co +nnected. February 14 15:32:43 localhost[32293]: Client sent data +: HUP February 14 15:32:43 localhost[32293]: Server sent HUP +by client! February 14 15:32:43 localhost[32293]: Server has stopp +ed - we need to restart! February 14 15:32:43 localhost[32293]: RESTART: /usr/bi +n/perl,,

-=( Graq )=-

Replies are listed 'Best First'.
Re: My daemon will not restart
by pc88mxer (Vicar) on Feb 14, 2008 at 16:53 UTC
    A simple solution would be to create the socket with SO_REUSEADDR. You can do it with IO::Socket::INET, but I'm not sure if EasyTCP allows you to do it. For an example of server which uses this socket option, see this node.

    The problem is that when you shutdown your server the port still has a connection which is in the TIME_WAIT state. This is a way to make sure that all traffic on that connection has ceased. The TIME_WAIT timeout can vary, but it usually is at least 30 seconds.

      A simple solution would be to create the socket with SO_REUSEADDR...but I'm not sure if EasyTCP allows you to do it.

      That was my first suspicion too, but Net::EasyTCP creates sockets with SO_REUSEADDR by default. From Net::Easy_TCP->_new_server():

      $sock = new IO::Socket::INET( LocalPort => $para{port}, Proto => 'tcp', Listen => SOMAXCONN, Reuse => 1, );

      All dogma is stupid.

      I set up a socket 'manually', just after the $server undef, and before restart:

      . . $log->warning('Server has stopped - we need to restart!'); $server = undef; use IO::Socket::INET; use IO::String; my $listen = IO::Socket::INET->new( Listen => 5, LocalAddr => 'localhost', LocalPort => 12345, Proto => 'tcp', ReuseAddr => 1 ); while( 1 ){ $log->warning( "listening....\n" ); sleep 5; } &restart_daemon; . .

      The client seems quite happy to connect to this newly created socket..

      I am really baffled.

      -=( Graq )=-

Re: My daemon will not restart
by tirwhan (Abbot) on Feb 14, 2008 at 17:04 UTC

    Do you close the open socket in your sub release_the_pid_file()? (Not shown in the source you provide)(Update:Just noticed that this is a sub of Proc::PID_File)

    You're not closing the open socket. The system may not yet have disassociated the open socket with your old process, and the new one will be unable to bind to it (you can't have two processes listening to the same TCP port). The subsequent die "Failed to restart daemon" will never be reached because it's after the exec.

    All dogma is stupid.
      This is a good suggestion. If you add:

      $server = undef;
      right before (or in) the call to &restart_daemon, things might work for you (at least they did in a stripped down version of your code.)
        I have undefing $server, as well as explicitly undefing $server->{_sock}, but with no change in behaviour.

        -=( Graq )=-

Re: My daemon will not restart
by Anonymous Monk on Feb 14, 2008 at 15:44 UTC
    Where is the SERVER output?

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://667943]
Approved by Old_Gray_Bear
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (3)
As of 2022-09-24 16:32 GMT
Find Nodes?
    Voting Booth?
    I prefer my indexes to start at:

    Results (114 votes). Check out past polls.