I have daemon script which runs forever in while loop. I have a prepared statement and this statement is executed on every loop.
Example:
my $dbh;
sub get_dbh {
return DBI->connect(...);
}
my $dbh = get_dbh();
my $sth = $dbh->prepare("SELECT ....") or die $DBI::errstr;
while (1) {
// is connection still there??
//if (!$dbh->ping) {
// $dbh = get_dbh();
//}
$sth->execute('param1');
// do some other things ... sleep between 0 and 3600
}
Problem occurs (or might occur) if prepared statement is prepared a few hours ago. Connection could die and my execute too. Checking $dbh->ping before every execute looks like an overkill.
MySQL supports mysql_auto_reconnect which works really. DBD::Pg doesn’t have something like that. I read about DBI::Apache but as I see it depends on mod_perl etc. It is obviously meant for web applications.
Is there a “best-practice” way to do check for connection state and reconnect if needed?#
I could prepare statement on every loop but that is not the solution but just a way around the problem.
Yes, at least in my view, because there’s only one approach that’s free of race conditions, and that’s to execute the query in a retry loop that handles errors if they arise.
Otherwise you still have:
PREPARESELECT 1;or whatever your test statement isEXECUTECorrect behaviour requires something like the pseudocode:
Verbose and annoying? Yep, but usually easily wrapped in a helper or library. Everything else is still subject to races.
Most importantly, if your application is issuing transactions where it does more than one thing, it needs to remember everything it did until the transaction commits, and be able to retry the whole transaction if there’s an error. That, or tell the user “oops, I ate your data, please re-enter it and try again”.
If you don’t mind the races and just want to handle any obviously dead connections with a periodic check, just store the time of the last query in a variable. When issuing queries check if the timestamp is more than a few minutes old and if it is, issue a
SELECT 1;or a query againstpg_prepared_statementsto check for your prepared statement. You’ll either need to be prepared to barf errors at the user or wrap the whole thing in proper error handling anyway … in which case there’s no point bothering with the time check and test at all.