Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

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

by superfrink (Curate)
on Apr 18, 2008 at 23:51 UTC ( [id://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).

Replies are listed 'Best First'.
Re: IPC::Open3::Simple closes database connection on error.
by ikegami (Patriarch) 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 <frank@revsys.com>
    www.revsys.com

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 (Patriarch) 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?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
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?Last hourOther CB clients
Other Users?
Others scrutinizing the Monastery: (7)
As of 2024-03-28 18:56 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found