rsiedl has asked for the wisdom of the Perl Monks concerning the following question:

Hi monks,

I've got a question about writing perl scripts which die 'properly' when killed.

Basically I've got some scripts that access MySQL databases and I've noticed that when I 'Ctrl^C' them or 'kill -9' them, the connection to the MySQL database hangs around for a while. Is there a way of writing a script so that when it is killed prematurely, it will close of the connection to the database quicker?

I use $dbh->disconnect, but of course this only works if the script gets to execute it...

Cheers,
Reagen

Replies are listed 'Best First'.
Re: killing perl scripts
by ysth (Canon) on Dec 13, 2004 at 13:08 UTC
    For Ctrl^C or kill -INT, use a signal handler:
    $SIG{INT} = sub { $dbh->disconnect if $dbh };
    AFAIK, nothing you can do about kill -9; perhaps you oughtn't to be using -9 habitually?
Re: killing perl scripts
by rev_1318 (Chaplain) on Dec 13, 2004 at 14:14 UTC
    to make sure that most signals will trigger the closing, use an END-block:

    END { $dbh->disconnect }
    in conjunction with sigtrap to trap al signals (which are trappable!):

    use sigtrap qw(die normal-signals);

    Paul

Re: killing perl scripts
by radiantmatrix (Parson) on Dec 13, 2004 at 14:57 UTC

    Both ysth and rev_1318 make excellent points. But, be careful with SIG handlers. 'kill -9' should be an ultimately last resort if nothing else works, not just a way to kill a script. If you read the perldoc on signals and the POSIX module POD, you should get a much better idea of what (and what not) to do.

    Because I have read those, and know a bit about signals, I will mention one thing further; try to avoid setting $SIG{KILL} unless you're positive you know what you're doing. If your KILL handler doesn't work properly, you may find yourself up a very smelly stream without an appropriate nautical navigation tool. ;-)

    radiantmatrix
    require General::Disclaimer;
    s//2fde04abe76c036c9074586c1/; while(m/(.)/g){print substr(' ,JPacehklnorstu',hex($1),1)}

      On my system at least, you can't catch KILL. This code prints KILL signal caught when KILL is caught:
      [gifford@gifford gifford]$ perl -e'$SIG{KILL}=sub { die "KILL signal c +aught"; }; sleep(10)' & [1] 4316 [gifford@gifford gifford]$ kill -9 4316 [gifford@gifford gifford]$ [1]+ Killed perl -e'$SIG{KILL}=sub { die "KILL signa +l caught"; }; sleep(10)'

        Yes, that is how it should work. However, I have seen the occasional two-stage KILL signal, where kill -9 sends SIGKILL only truly destroys the process if the SIG is not handled by the application after few ticks.

        I don't know how common that is, but it's still unwise to set $SIG{KILL} unless you know for sure it will be safe to do so.

        radiantmatrix
        require General::Disclaimer;
        s//2fde04abe76c036c9074586c1/; while(m/(.)/g){print substr(' ,JPacehklnorstu',hex($1),1)}

Re: killing perl scripts
by Possumfoot (Initiate) on Dec 14, 2004 at 19:48 UTC
    I'd like to add another layer of complexity. I connect to MySQL from a CGI::Application web app. CA recommends using a teardown sub to disconnect as follows:
    sub teardown { my $self = shift; # Disconnect when we're done $self->param('DBH')->disconnect(); } # teardown
    Is this sufficient, or should I also worry about those cases where the script dies in midstream?