Link to home
Start Free TrialLog in
Avatar of jakac
jakac

asked on

Perl daemon + fork + DBI persistent database connection

I am running a simple daemon using libwww's HTTP::Daemon module.. Main code looks like this (I just deleted things that don't have to do anything with my question):


-----------------------------------------
local $SIG{CHLD} = 'IGNORE';

# &connectDB should be executed here

  my $server;
  unless (defined $server) {
  $server = new HTTP::Daemon
        LocalAddr => $Config{'host'},
        LocalPort => $Config{'port'} || die "Can't start daemon!";
     }

  while (my $connection = $server->accept) {

# Fork a child process for the connection (beginning of the child process)
     if (my $pid = fork) {
         next;
     }

      while (my $request = $connection->get_request) {
# here's where the *magic* takes place      
      }
      $connection->close;
      undef $connection;
      exit;
# end of the child process
  }

# &disconnectDB should be executed here

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


Well generally pretty simple. But now I want this daemon to have a persistent connection to a database using DBI.
I managed to do this with PostgreSQL by using "InactiveDestroy => 1" parameter. But I ran into some problems because after a few requests Postgres hangs up and dies producing zombies. This happens because of some sort of bug in libpq (if I understand correctly what is going on), but no one can really help me to fix this error (Backend message type 0x50 arrived while idle). So now I am trying to do the same thing with MySql which ignores this InactiveDestroy parameter and database connection gets lost after the child exits.
The code above should call procedure to connect to database before forking child process and then child process should execute some queries (*magic*) through this connection and then child should die but parent should stay connected to database. Postgres was working like this just fine but after a few requests that 0x50 error message arrived and all childs became zombies and didn't exit afterwards. But with MySql database connection is lost after first child has finished executing queries and exited.
What am I supposed to do?
I know that I can connect to database at the beginning of child and disconnect before child exits, but that solution is not any good for me - too slow and too much connections to database at once.
ASKER CERTIFIED SOLUTION
Avatar of Sapa
Sapa

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of jakac
jakac

ASKER

I have just another question for you before I accept Comment as answer (your answer is excellent!!). Before I modified my server using your code I was starting my server like ./server.pl start - that still works OK, writes a PID file so then ./server.pl stop kills that pid. Before everything was OK, but now if I look at the processes while server is running it looks like this:

jakac@ns:~/Server$ ps axj | grep server.pl
    1 13224 13224 13224 ?           -1 S     1001   0:00 perl -w ./server.pl start
13224 13226 13224 13224 ?           -1 S     1001   0:00 perl -w ./server.pl start
13224 13227 13224 13224 ?           -1 S     1001   0:00 perl -w ./server.pl start
13224 13228 13224 13224 ?           -1 S     1001   0:00 perl -w ./server.pl start
13224 13229 13224 13224 ?           -1 S     1001   0:00 perl -w ./server.pl start
13224 13230 13224 13224 ?           -1 S     1001   0:00 perl -w ./server.pl start
13224 13231 13224 13224 ?           -1 S     1001   0:00 perl -w ./server.pl start
13224 13232 13224 13224 ?           -1 S     1001   0:00 perl -w ./server.pl start
13224 13233 13224 13224 ?           -1 S     1001   0:00 perl -w ./server.pl start
13224 13234 13224 13224 ?           -1 S     1001   0:00 perl -w ./server.pl start
13224 13235 13224 13224 ?           -1 S     1001   0:00 perl -w ./server.pl start

Ok - so 13224 is parent and others are childs.. But if I do ./server.pl stop - code for this looks like this:

---
local (*PID);
open(PID,"<server.pid");
while (my $line = <PID>) {
    chop($line);
    if (! kill 9, $line) {
     print "Cannot kill process $line!\n";
    } else {
     print "Killed process $line.\n";
    }
}
close(PID);
open(PID,">server.pid");
close(PID);
---

here's what happens:

jakac@ns:~/Server$ ./server.pl stop    
Killed process 13224.
jakac@ns:~/Server$ ps axj | grep server.pl
    1 13226 13224 13224 ?           -1 S     1001   0:00 perl -w ./server.pl start
    1 13227 13224 13224 ?           -1 S     1001   0:00 perl -w ./server.pl start
    1 13228 13224 13224 ?           -1 S     1001   0:00 perl -w ./server.pl start
    1 13229 13224 13224 ?           -1 S     1001   0:00 perl -w ./server.pl start
    1 13230 13224 13224 ?           -1 S     1001   0:00 perl -w ./server.pl start
    1 13231 13224 13224 ?           -1 S     1001   0:00 perl -w ./server.pl start
    1 13232 13224 13224 ?           -1 S     1001   0:00 perl -w ./server.pl start
    1 13233 13224 13224 ?           -1 S     1001   0:00 perl -w ./server.pl start
    1 13234 13224 13224 ?           -1 S     1001   0:00 perl -w ./server.pl start
    1 13235 13224 13224 ?           -1 S     1001   0:00 perl -w ./server.pl start


Parent is killed and all childs become parents and then I have to manually kill them... Any idea how to modify this "server.pl stop" function to kill all processes - parent and all childs?
BTW: Will increase question points before I accept your answer!
Hi,

I don't know what server.pid contains in. If it contains
parent PID only, you should kill process group instead of one process. Just send negative signal:

kill -9, $pid;

instead of:

kill 9, $pid;

If server.pid contains list of all PID's - parent and children, your code should works ok.

Andrey

P.S. look 'perldoc -f kill' about negative signal values.
Avatar of jakac

ASKER

Thanx for your help!