Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris

IPC::Open3::Simple closes database connection on error.

by superfrink (Curate)
on Apr 18, 2008 at 23:51 UTC ( #681600=perlquestion: print w/replies, xml ) Need Help??
superfrink has asked for the wisdom of the Perl Monks concerning the following question:

When I attempt to run a command that does not exist using IPC::Open3::Simple a postgres database handle in the script gets closed.

The following code reproduces the problem. There are two $ipc->run lines. Comment one or the other out to see the different behaviour. There are several $dbh->ping lines used to narrow down where the connection was being dropped.
#! /usr/bin/perl -w use strict; use Data::Dumper; use DBD::Pg; use IPC::Open3::Simple; $| ++; my $DB_NAME = 'db_name'; my $DB_USERNAME = 'db_username'; my $DB_PASSWORD = '12345678'; # log in to the database my $dbh = DBI->connect("dbi:Pg:dbname=$DB_NAME", $DB_USERNAME, $DB_PASSWORD, ) or die $DBI::errstr; $dbh->trace(0); # now run a query to make sure the database connection works my $sth; unless ($sth = $dbh->prepare("select now()")) { warn "Unable to prepar +e SQL."; } unless ($sth->execute()) { warn "Unable to execute SQL."; } $sth->finish; print "ping " , __LINE__ , " " , $dbh->ping, "\n"; # now run a command that fails my (@cmd_output, @err_output); my $ipc = IPC::Open3::Simple->new( in => sub { my $fh = shift; print $fh "mydata"; close $fh; } , out => sub { push @cmd_output, $_[0]; } , err => sub { push @err_output, $_[0]; } , ); print "ping " , __LINE__ , " " , $dbh->ping, "\n"; #$ipc->run('date'); # this line is fine $ipc->run('no-such-command'); # this line causes the problem print "ping " , __LINE__ , " " , $dbh->ping, "\n"; print Dumper("output:", \@cmd_output, "error:", \@err_output), "\n"; print "ping " , __LINE__ , " " , $dbh->ping, "\n"; # now run another database query unless ($sth = $dbh->prepare("select now()")) { warn "Unable to prepar +e SQL."; } print "ping " , __LINE__ , " " , $dbh->ping, "\n"; unless ($sth->execute()) { warn "Unable to execute SQL."; } print "ping " , __LINE__ , " " , $dbh->ping, "\n"; $sth->finish; $dbh->disconnect() or die $DBI::errstr; exit 0;
The successful run looks like:
ping 30 1 ping 41 1 ping 46 1 $VAR1 = 'output:'; $VAR2 = [ 'Fri Apr 18 17:34:43 MDT 2008' ]; $VAR3 = 'error:'; $VAR4 = []; ping 50 1 ping 54 1 ping 56 1

The failing run looks like:
ping 30 1 ping 41 1 ping 46 0 $VAR1 = 'output:'; $VAR2 = []; $VAR3 = 'error:'; $VAR4 = [ 'Can\'t exec "no-such-command": No such file or directory at + /usr/lib/perl5/5.8.8/IPC/ line 246.', 'open3: exec of no-such-command failed at /usr/lib/perl5/sit +e_perl/5.8.8/IPC/Open3/ line 61' ]; ping 50 0 ping 54 0 DBD::Pg::st execute failed: no connection to the server at reproduce-c line 55. Unable to execute SQL. at line 55. ping 56 0

After working on it for a while I suspect the IPC::Open3::Simple code ends up doing something like the following:

* fork a child process. This process is a copy of the parent (ie it is a perl process).
* The child process tries to exec the command.
* The command does not exist so exec fails.
* The child perl process exits and closes the database handle it copied from the parent.

I am thinking of adding code to check to see that the first argument in the command to be executed is a readable, executable file.

Any other ideas of how to not have the database connection close?

Update: I should also mention there is nothing showing up in the postgres server log file (just autovacuum entries).

Replies are listed 'Best First'.
Re: IPC::Open3::Simple closes database connection on error.
by ikegami (Pope) on Apr 19, 2008 at 00:46 UTC

    If POSIX can be loaded, then _exit is used on exec failure.

    exec @cmd or do { carp "$Me: exec of @cmd failed"; eval { require POSIX; POSIX::_exit(255); }; exit 255; };

    Using _exit should avoid the problem because _exit doesn't allow destructors to be run.

    >perl -MPOSIX -le"DESTROY{print q{foo}}$o=bless{};$ARGV[0]?_exit 1:exi +t 1" 1 >perl -MPOSIX -le"DESTROY{print q{foo}}$o=bless{};$ARGV[0]?_exit 1:exi +t 1" 0 foo

    Could there be a problem loading POSIX?

Re: IPC::Open3::Simple closes database connection on error.
by ides (Deacon) on Apr 19, 2008 at 00:39 UTC

    After looking over the code, IPC::Open3::Simple doesn't do any forking, but it uses IPC::Open3 which does. So you are probably right about the cause.

    I would definitely check for existance, readability, and execute bits before running it. I would also just run your ping, and if it fails reconnect to the database. That should cover all possibilities.

    Frank Wiles <>

Re: IPC::Open3::Simple closes database connection on error.
by tilly (Archbishop) on Apr 19, 2008 at 01:40 UTC
    Nothing would show up in the database log because the connection closes properly. After that it doesn't even notice that someone was jabbering to a socket that wasn't there.

    The general solution to this kind of problem is to set InactiveDestroy on the database handle in the children. I suppose you could try setting InactiveDestroy on the handle in your script before the IPC::Open3::Simple call, and then unset it after the call.

Re: IPC::Open3::Simple closes database connection on error.
by pc88mxer (Vicar) on Apr 19, 2008 at 07:00 UTC
    You might be able to get around this problem by using
    $ipc->run("/bin/sh your-command")
    or use some other program which will always exist to exec your command.
Re: IPC::Open3::Simple closes database connection on error.
by ikegami (Pope) on Apr 19, 2008 at 03:09 UTC
    You won't have this problem on a Windows machine, since open3 spawns a child process instead of calling fork on those machines. That probably didn't help, but just in case.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://681600]
Approved by lidden
Front-paged by almut
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others pondering the Monastery: (6)
As of 2018-06-18 23:43 GMT
Find Nodes?
    Voting Booth?
    Should cpanminus be part of the standard Perl release?

    Results (111 votes). Check out past polls.