This led me to create DBIx::Timeout which instead of using unsafe signals:
- 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
- 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.
Tim Bunce suggested a possible optimization - fork just one child process and have it watch any number of slow queries simultaneously. It would accept assignments via a pipe interface. Seems like a good idea, although it's likely overkill for my usage. The queries I need to timeout are very likely to be long-running, and when they're not don't need to be very fast. The overhead of forking a process that exits almost immediately won't cause any problems, I'm betting.
So, please give it a try! And if you're not a MySQL user, please port it to your DB and send me a patch. It should be an easy job - all you have to do is implement a call to kill another process in the DB (MySQL does it with "KILL $thread_id"). (UPDATE: actually, it's a little more work - you also need to write new tests. The tests I wrote for MySQL use GET_LOCK() to test timeouts - you'll need to do something analgous for your DB.)
PS: I should note that the mechanism this module uses was suggested by my co-worker Perrin Harkins. I'll add that to the module's POD for the next release.