Reputation: 3651
I have the following code running to catch any SQL statements that might get hung. While trying to test this, I wrote a horibly optimized sql statement that takes over a minute to run. I put a 20 second timeout wrapper around an activerecord execute sql statement, but it doesn't seem to interrupt the sql call for taking to long. This is running against Oracle databases.
start_time = Time.now
Timeout.timeout(20) do #20 timeout for long running sql
@connection.connection.execute(sql_string)
end
total_sql_time = Time.now - start_time
puts "Sql statement took #{total_sql_time} seconds
output
Sql statement took 64 seconds
Upvotes: 3
Views: 1491
Reputation: 78443
(Just a guess…)
Ruby's Timeout.timeout()
is probably operating in much the same way as the equivalent function in PHP, which is to say that it counts time executed within Ruby, and stops counting when you're waiting for database queries to run, waiting to finish reading or writing files, waiting to for a network request to complete, etc. — i.e. waiting for anything IO-related.
Upvotes: 2
Reputation: 1993
Remember that ActiveRecord is an ORM, which is to say it's a layer of abstraction that sits on top of your database.
This is important in the context of what happens when Timeout.timeout
executes. Database adapters are responsible for taking a command in ruby and converting them into commands that are executed in your database, an entirely different process.
When a timeout happens, the call to @connection.connection.execute
, as a ruby command, is interrupted in the adapter but not the sql code itself as you've noted.
You should be able to make use of the optional Exception Class parameter klass
in Timeout.timeout
to specify a signal/command to send to your database in order to cancel the query itself. However this would depend on your database adapter. Here's the kill query
command I would try to execute if I were using mysql.
Upvotes: 1
Reputation: 10582
Admittedly, I don't have much experience with Rails backed by Oracle, but there's the timeout option in the database config file.
# config/database.yml
production:
...
timeout: 20000
It's in milliseconds.
If I can assume you are in the development environment, you might want to explicitly set your explain
timeout and review the console log:
# config/environments/development.rb
config.active_record.auto_explain_threshold_in_seconds 20
Upvotes: 1