I’ve got a simple Perl script that listens on a network port, accepts data and writes things to a databse using DBD::ODBC. It looks a little bit like this:
#!/usr/bin/perl
my $dbh = DBI->connect('dbi:ODBC:SqlProd',"yay","ooo",{AutoCommit => 0}) || die "Couldn't connect to db";
my $sth = $dbh->prepare("insert into table some stuff");
$sock = IO::Socket::INET->new(LocalPort => '1234', Proto => 'udp')||die("Socket: $@");
do {
$sock->recv($buf, $MAXLEN);
/*parse some data here*/
/*bind some parameters to $sth here*/
my $rv = $sth->execute() || warn logit('warning', "Error inserting to db: $! $msg");
$dbh->commit() || warn logit('err',"Error committing db transaction: $! $msg");
}while(1);
This, while being a little crude, works fairly well. However, for reasons unknown, the database goes down and the script crashes saying things like:
DBD::ODBC::st execute failed: [unixODBC][FreeTDS][SQL Server]Write to the server failed (SQL-08S01) at /usr/local/bin/haproxy-syslog line 117.
0 at /usr/local/bin/haproxy-syslog line 117.
DBD::ODBC::db commit failed: [unixODBC][FreeTDS][SQL Server]Could not perform COMMIT or ROLLBACK (SQL-HY000) at /usr/local/bin/haproxy-syslog line 118.
Error committing db transaction: Connection reset by peer
DBD::ODBC::db DESTROY failed: [unixODBC][FreeTDS][SQL Server]Could not perform COMMIT or ROLLBACK (SQL-HY000) during global destruction.
If I wanted the script to be resiliant to this sort of failure, either by just waiting for a set amount of time and seeing if the database was awake again, or dropping the data received and pulling more data in from the socket, what would be the best way of going about it? Does the above error mean that $dbh ends up being junk and needing to be re-initialized?
The problem is caused because even though the execute() fails, you are still calling commit(). Since there is no connection, you can’t send the DB the commit call. Also, it appears you have AutoCommit on so that the DB tries to close any open transactions when disposing of the connection in the DESTROY call.
You could try something like this (forgive my rusty perl):