moderated >> Net::Daemon Q: Rereading caches in the "master" process?

by Paul Smith » Fri, 30 Sep 2005 23:35:51 GMT

Not sure this is the best place to post, but:

I have a Perl daemon using Net::Daemon (technically it uses
RPC::PlServer, which inherits from Net::Daemon).

When the daemon starts up, it reads a bunch of system configuration
information into internal hashes etc., then invokes Bind() to wait for
requests. I'm using the fork model and that works fine and I want to
keep using it (allows concurrent client support, doesn't mess with
threads).


Here's the thing: sometimes the configuration files on the system
change. I'd like to enhance my daemon so that it could detect these
changes itself and reload the cached information.

Today what happens is that the child process that's forked detects the
changes and re-reads the cache... but then the whole idea of the cache
is not very useful because the child process exits, and the next one
has to do the same thing. This is OK for a little bit, but it sucks
over the long term.

What I need to do is get the master daemon process to reread IT'S
caches, so that future children will have up-to-date caches and won't
have to go through that work.

I'm not sure the best way to do it, though. Looking at the man page for
Net::Daemon it seems I only have one option: set the loop-timeout
parameter, then create a Loop() method that re-reads the caches. The
man page recommends also setting the loop-child parameter, but of course
that would defeat the entire purpose so I wouldn't do that.


Is this the only way? The best way? Other suggestions? Things I
should be careful about?

It would be nicer if there were some way for the child to signal the
parent that its caches are dirty, so they can be updated immediately
instead of once every N minutes or whatever with Loop(), but that's not
critical.

Cheers!

--
-------------------------------------------------------------------------------
Paul D. Smith < XXXX@XXXXX.COM > HASMAT--HA Software Mthds & Tools
"Please remain calm...I may be mad, but I am a professional." --Mad Scientist
-------------------------------------------------------------------------------
These are my opinions--Nortel takes no responsibility for them.

Similar Threads

1. Caching results (?) of lengthy cgi process

Folks:

I'd look this up in the Perl docs, if I could figure out what to call it.

Consider: Perl "results.cgi" generates a perfectly good page of juicy
results, except it takes much too long in human time to do it, over 30
seconds -- and it is likely to get longer, not shorter.

In fact, the results don't change very often, so the hard work only needs to
be done periodically, maybe every couple of weeks.   So, most of the time,
there's no need to have the user wait for a full update.

I can see two obvious, possibly nae, ways to minimize computation time for
most accesses to the results:

1)  Arrange for "update_results.cgi" to run every few weeks and write
plain-old "results.html" which replaces "results.cgi", or

2) Write "update_results.cgi" to compute the data and put it in a safe place
(e.g. file "results.dat") and have "results.cgi" grab the stuff from there.

Is there a better way?

Is there any special terminology/methodology  or  Perl language
features/modules to support this kind of design?

Thanks,

Henry

 XXXX@XXXXX.COM   remove 'zzz'

2. Caching results (?) of lengthy cgi process...mirroring - Perl

3. forks from within a perl daemon process?

Hi,

I have a program that I have been running via cron that I thought might
be better run by running it as a daemon. When I created some test
daemon programs they all worked. When I placed my program inside of the
while loop, I noticed that the daemon killed its self somehow. I then
figured out that it died just after it tried launching a new fork
process -- and when I commented this out it worked fine.

I made some sample code based on how I am doing this. I have it set to
print output to the screen. I have it below to not use threads. That
will let you see what it is supposed to do. Then, if you uncomment the
'use forks' statement, comment the line beginning with &browserbuilder,
and uncomment the line starting with ${$i}=threads you will see what it
does in a threads-based setup.

Can anyone provide any insight in to why this is not working and
perhaps give some advice for what I need to do?

Thanks,
~dave

PS> I would like to use forks instead of threads although I have them
both in the program for testing.

----------------------------


#!/usr/bin/perl

use POSIX qw(setsid);

&daemonize;

#use forks;
#use threads;
#uncomment one of two above modules to use that package for threading
use strict;

while(1) {

my (@urls,@urls2,$ib,$i);
$ib="a";
print "Started at " . `date` . "\n\n";

@urls=qw/1 2 3 4 5 6 7 8 9 10/;

foreach my $xurlid(@urls)
{

        $i=$ib . $xurlid; #makes each thread object unique by adding
it's url id to '$ib' defined above
        print "about to fork $xurlid thread\n";
        #${$i}=threads->create(\&browserbuilder, $xurlid, 'dave');
        #uncomment above to use thread-based setup
        &browserbuilder($xurlid,'dave');
        #uncomment above to use non-thread setup
        push @urls2, $i; #used for checking thread status later
        select(undef, undef, undef, 0.07); #sleep for 70 milliseconds
}

###########
# Go through each thread and wait for it to close so the program
doesn't exit early
#foreach my $url(@urls2)
# {
#  @{$url} = ${$url}->join();
#  print "$url returned: ${$url}[0]\n";
# }
###########
print "Ended at " .  `date` . "\n\n";
sleep 10;
}
#end loop

sub browserbuilder
{

my $num=shift @_;
my $name=shift @_;

print "\n$name forked $num correctly\n\n";
return 0;

}

sub daemonize {
    chdir '/'                 or die "Can't chdir to /: $!";
    open STDIN, '/dev/null'   or die "Can't read /dev/null: $!";
#    open STDOUT, '>>/var/log/uu_info.log' or die "Can't write to
/dev/null: $!";
    open STDERR, '>>/var/log/uu_errors.log' or die "Can't write to
/dev/null: $!";
    defined(my $pid = fork)   or die "Can't fork: $!";
    exit if $pid;
    setsid                    or die "Can't start a new session: $!";
    umask 0;
}

4. Multi-process Win32 HTTP Daemon - Perl

5. Questions about perl daemons with child processes and open files / signals

  Hi, I have some questions about perl codes
running as daemon which launch a child process.
I need to run a perl script as a daemon. The
script will monitor tcpdump's output. At first
my script was using a temp file to store the
tcpdump output, but I decided to use a pipe
instead (and did not want to run my script piped
on the command line: tcpdump | ./foo . I wanted
to include the pipe to tcpdump in the script).

  The best way I found to do this is by creating
a child process for tcpdump, because running:
 open LOGTMPFILE, "tcpdump -i ne1 2> /dev/null |";
do not return the control to the script until
tcpdump terminated. I'm doing it in starttcpdump()
and it works very well, but I'm not sure that
it's the best way to do this.

  Another thing I wanted is to be able to call
my script like this to terminated the running
daemon:
~$ foo stop

  Here I have a problem, what I planned to do
was catching signals in the script to make some
cleanup before terminating the script:
 - kill the child process
 - close the tcpdump open pipe (LOGTMPFILE)
if I don't do this, tcpdump continues to run
when the script ends. The problem I have is
that only the child process can close the
LOGTMPFILE file. So I tought I should kill the
child process first (which close the tcpdump
pipe) and then ask the child process to close
the parent process. I also tried to close the
parent process, thinking it would automatically
close the child and tcpdump pipe. but it does
not work. Everything I tried seems to hang at
close LOGTMPFILE and never give back the control
to the script.

The best I was able to get, is have both instances
of perl (parent and child) killed, but tcpdump
still running. By the way it seems to work well
if I press CTRL-C will running the script normally
(not as daemon). the tcpdump process is killed.

Here are my questions:

- I'm I doing tcpdump pipe launching the right
  way? it's the best way I found to do this. But
  it takes more memory (another instance of the
  process). Is there a better way. I do not want
  to use temp files.

- Is there anything wrong with my daemon mode
  subroutine?

- How can I modify my code to be able to kill
  everything: parent, child and tcpdump processes.

- Which signal should I use to stop the script?
  HUP, INT, QUIT ?

Any suggestions and tips would be greatly appreciated.

Thanks in advance.

Here a very simplified version of my code. I didn't
test it and it may not run correctly. But it
demonstrate what I want to achieve, I have removed
a lot of things for code simplicity like every
"or die ..." tests and irrelevant code:

#!/usr/bin/perl

use FileHandle;
use POSIX;

if ($ARGV[0] eq "stop")
{
  print "Terminating process ...\n";
  sendterminatesig ();
  exit 0;
}

createdaemon();
starttcpdump ();

$SIG{INT} = \&signalhandler;

while (1)
{
  # do something
}

exit 0;

sub createdaemon ()
{
    # for problems on mounted partitions
    chdir '/';

    umask 0;

    # fork() a child process and have the parent process exit()
    my $pid = fork;
    exit if $pid;
    die "\nError: Couldn't fork: $!\n" unless defined $pid;

    open  (PIDFILE, ">/var/run/foo.pid");
    printf PIDFILE "%d\n", POSIX::getpid();
    close (PIDFILE);

    # so it doesn't have a controlling terminal.
    POSIX::setsid();

    open STDIN, '/dev/null';
    open STDOUT, '>/dev/null';
    open STDERR, '>/dev/null';
}

sub starttcpdump ()
{
  if (!defined(my $kidpid = fork()))
  {
    # fork returned undef, so failed
    die "\nError: Cannot fork: $!\n";
  }
  elsif ($kidpid == 0)
  {
    # fork returned 0, so this branch is the child
    open LOGTMPFILE, "tcpdump -i ne1 2> /dev/null |";

    open  (PIDFILE, ">/var/run/foo.child.pid");
    printf PIDFILE "%d\n", POSIX::getpid();
    close (PIDFILE);
  }
  else
  {
    # so this branch is the parent
    waitpid($kidpid, 0);
  }
}

sub sendterminatesig ()
{
    if (-e "/var/run/foo.pid")
    {
      # Open and read pid file
      open  (PIDFILE, "/var/run/foo.child.pid");
      my $childpid = <PIDFILE>;
      close (PIDFILE);

      # sending message to process
      if (kill 0 => $pid)
       {
       	  # Here I tried: calling the parent process
       	  # first, so it close the tcpdump pipe, but
       	  # it doesn't work. I also tried calling the
       	  # child process then the parent process, but
       	  # the tcpdump process is not closed. Then I
       	  # tried to call the child process to close the
       	  # pipe (in signalhandle) and ask the child process
       	  # to kill the parent (still in signalhandle).
       	  # None of them works.

          kill INT => $childpid;

          exit 0;
       }
      elsif ($! == EPERM)
       {  # changed uid
          print "\nError: foo (pid:$pid) has escaped my control!\n";
          exit 1;
       }
      elsif ($! == ESRCH)
       {  # process not found or zombied
          print "\nError: foo (pid:$pid) is deceased.\n";
          exit 1;
       }
      else
       {
          print "\nError: couldn't check on the status: $!\n";
          exit 1;
       }
    }
    else # pid file not found, quit
    {
      print "\nError: pid file not found!\n";
      exit 1;
    }
}

sub signalhandler
{
    my $signame = shift;

    # Child process
    if (-e "/var/run/foo.child.pid")
    {
     open  (PIDFILE, "/var/run/foo.pid");
     my $pid = <PIDFILE>;
     close (PIDFILE);

     close (LOGTMPFILE); # Close the tcpdump pipe

     kill INT => $pid;   # Kill the parent process

     unlink("/var/run/foo.child.pid");
    }
    else # Parent process
    {
     unlink("/var/run/foo.pid");
    }
      
    exit 0;
}

6. Backtick call dies in child process inside daemon - Perl

7. Errant MAIERL-DAEMON messages from mail9.mxpath.net

HI Casey,

Can you get  XXXX@XXXXX.COM  off this list?
His ISP's MAILER_DAEMON is spamming the list with
error messages.  My policy is to forward a correction
for each to  XXXX@XXXXX.COM  until they
stop.

Joseph

8. Net::Daemon::SSL