Search code examples
postgresqlperl

How can you prevent forked child processes from disconnecting DBD::Pg connections, when you have no access to $dbh?


I have a library that needs to fork() to fire-and-forget some code. However when the child process spawned by fork() is destroyed, the DBD::Pg's END is called and inadvertently kills the parents connection. On-top of this, the code has no access to the $dbh, and can't use DBI.

Here is some code that reproduces the issue:

use strict;
use warnings;

use DBI;

my $dbh = DBI->connect('dbi:Pg:dbname=foo', '', '');

if (!fork()) {
  CORE::say 'In child, doing stuff!';
  exit 0;
}

sleep 2; # Provide adequate time for the child to be reaped.


my $sth = $dbh->prepare(q[select NOW();]);
$sth->execute(); # Error! Something, something, connection terminated!
my $time = $sth->fetch->[0];
CORE::say "It is $time o'clock";

Here is the error:

DBD::Pg::st execute failed: server closed the connection unexpectedly
    This probably means the server terminated abnormally

Solution

  • Instead of using exit, you can use POSIX::_exit, this causes END's to not be evaluated when the child exits.

    use strict;
    use warnings;
    
    use POSIX;
    
    use DBI;
    
    my $dbh = DBI->connect('dbi:Pg:dbname=foo', '', '');
    
    if (!fork()) {
      CORE::say 'In child, doing stuff!';
      POSIX::_exit(0);
    }
    
    sleep 2; # Provide adequate time for the child to be reaped.
    
    my $sth = $dbh->prepare(q[select NOW();]);
    $sth->execute(); # Error! Something, something, connection terminated!
    my $time = $sth->fetch->[0];
    CORE::say "It is $time o'clock";