Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

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/Open3.pm line 246.', 'open3: exec of no-such-command failed at /usr/lib/perl5/sit +e_perl/5.8.8/IPC/Open3/Simple.pm line 61' ]; ping 50 0 ping 54 0 DBD::Pg::st execute failed: no connection to the server at reproduce-c +rash.pl line 55. Unable to execute SQL. at reproduce-crash.pl 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).

Comment on IPC::Open3::Simple closes database connection on error.
Select or Download Code
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 <frank@revsys.com>
    www.revsys.com

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 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 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.
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.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://681600]
Approved by lidden
Front-paged by almut
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others having an uproarious good time at the Monastery: (13)
As of 2015-07-02 22:05 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The top three priorities of my open tasks are (in descending order of likelihood to be worked on) ...









    Results (45 votes), past polls