NAME

DBIx::Timeout - provides safe timeouts for DBI calls

VERSION

Version 1.00

SYNOPSIS

use DBIx::Timeout;

# run code() for a maximum of 5 minutes, doing work with $dbh
$ok = DBIx::Timeout->call_with_timeout(
  dbh     => $dbh,
  code    => sub { $dbh->do('LONG-RUNNING SQL HERE') },
  timeout => 300,
);

# handle the result
if (!$ok) {
  die "You ran out of time!";
}

DESCRIPTION

This module provides a safe method of timing out DBI requests. An unsafe method is described in the DBI docs:

http://search.cpan.org/~timb/DBI/DBI.pm#Signal_Handling_and_Canceling_Operations

The problem with using POSIX sigaction() (the method described above) is that it relies on unsafe signals to work. Unsafe signals are well known to cause instability. To understand why, imagine the DB client code is in the middle of updating some global state when the signal arrives. That global state could be left in an inconsitent state, just waiting for the next time it is needed to cause problems. Since this will likely occur far from the cause, and only occur rarely, it can be a very difficult problem to track down.

Instead, this module:

- Forks a child process which sleeps for $timeout seconds.

- Runs your long-running query in the parent process.

- If the parent process finishes first it kills the child and
  returns.

- If the child process wakes up it kills the parent's DB thread and
  exits with a code so the parent knows it was timed out.

NOTE: After this call your database connection may be killed even if no timeout occurred. This is due to a race condition - the child may wake up just as parent process finishes. Patches addressing this bug are welcome. Until this is fixed you should be ready to reconnect after call_with_timeout().

DATABASE SUPPORT

This release supports only MySQL. I would appreciate patches from users of other databases. Your patch will need to provide code to kill a running query. In MySQL this uses the KILL command, implemented in _kill_connection().

OPERATING SYSTEM SUPPORT

So far this code has been tested only on Linux. I expect it will work on any OS with normal fork(), kill() and waitpid() implementations. I do not expect it will work on Windows!

INTERFACE

call_with_timeout

$ok = DBIx::Timeout->call_with_timeout(
  dbh     => $dbh,
  code    => sub { $dbh->do('LONG-RUNNING SQL HERE') },
  timeout => 300,
);

This method calls code() with the specified timeout. You must also pass the database handle which will be used to execute the long-running query. This is the connection which will be killed if the timeout occurs.

The method will return 0 when a timeout is detected. Note that in either case the connection for $dbh may be killed after this method returns.

KNOWN ISSUES

When the timeout fires a warning may occur that looks like:

DBD::mysql::db selectcol_arrayref failed: Unknown error at ...

You can silence this warning by turning off PrintError:

$dbh->{PrintError} = 0;

I prefer RaiseError in any case.

BUGS

Please report any bugs or feature requests to bug-dbix-timeout@rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=DBIx-Timeout. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

SUPPORT

This module is supported on the dbi-users mailing list. Details here:

http://lists.cpan.org/showlist.cgi?name=dbi-users

You can find the public Subversion repository here:

https://dbix-timeout.googlecode.com/svn/trunk

CREDITS

The mechanism used by this module was suggested by Perrin Harkins.

AUTHOR

Sam Tregar, sam@tregar.com

COPYRIGHT & LICENSE

Copyright 2006 Sam Tregar, all rights reserved.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.