I'm using a firebird database gem to connect to a user specified database. It works fine as long as user provides correct data. If not, gem cannot connect, and it takes a very long time before gem throws an exception. I've tried to use Timeout:timeout like this:
database = Fb:Database(connection_data)
Timeout::timeout(5) do
database.connect #that's the part that takes long to connect
end
But it does not time out. It simply waits (and it is a long wait, more than a minute), and throws gem exception (it's not Timeout exception). It seems like the code executed below 5 seconds (according to Timeout), except it took it 1-2 minutes. I've been looking for an explanation (checking the source code as well), and didn't find any. I don't really want a fix to it (because it will be moved to delayed job anyway), but I would like to know why, and how can you ignore Timeout.
Also, the code below works fine.
Timeout::timeout(5) do
sleep(10)
end
The timeout block runs the code in a new thread and when the
timeout
happens after 5 seconds, the exception is forcefully raised (Thread.raise
I believe) into the thread runningdatabase.connect
. (Timeout module code)That interruption could happen on any line; it could be in some sort of rescue block in this case (and throwing a custom error after) or anywhere that does not handle it properly leaving it in an invalid state. It is highly unlikely for a library to be able to be coded defensively everywhere.
You can read more about the problems of using
Timeout::timeout
in this Reddit thread.