I am trying to implement a multithreaded method in rails such that I can create/update multiple records very quickly.
This is the outline of my program.
ActiveRecord::Base.transaction do
(1..10).each do |i|
arr[i] = Thread.new {
<some logic on obj>
...
...
obj.save!
}
end
arr.each {|t| t.join}
end
This gives me warnings on my log.
DEPRECATION WARNING: Database connections will not be closed automatically,
please close your database connection at the end of the thread by calling `close`
on your connection.
And it gives me an error
could not obtain a database connection within 5 seconds (waited 5.059358 seconds).
The max pool size is currently 5; consider increasing it.
I tried: - changing database.yaml and increasing the poolsize and timeout there. - modified the existing code in the following way.
ActiveRecord::Base.connection_pool.clear_stale_cached_connections!
begin
ActiveRecord::Base.transaction do
(1..10).each do |i|
arr[i] = Thread.new {
<some logic on obj>
...
...
obj.save!
ActiveRecord::Base.connection.close
}
end
arr.each {|t| t.join}
end
ensure
ActiveRecord::Base.connection.close if ActiveRecord::Base.connection
ActiveRecord::Base.clear_active_connections!
end
I am still getting the same warning and error. I am obviously missing the concept here. How do I proceed with this?
If you have a valid reason to keep it open, then do so. If not, close it as soon as you're done with it. But it's better to be in the good habit of closing the connections so that you don't just leave them open when you don't intend to.
For the purpose of safe coding, you should always close database connections explicitly to make sure that the code was able to close itself gracefully and to prevent any other objects from reusing the same connection after you are done with it.
Rails now has support for multiple databases so you don't have to store your data all in one place. At this time the following features are supported: Multiple writer databases and a replica for each. Automatic connection switching for the model you're working with.
To prevent connection leak in multi threads, you have to manage the connection manually. You can try:
Thread.new do
ActiveRecord::Base.connection_pool.with_connection do
# Do whatever
end
end
One problem of ActiveRecord::Base.connection_pool.with_connection
is that it always prepare a connection even if the code inside does not need it.
We can improve it a little bit by using ActiveRecord::Base.connection_pool.release_connection
:
Thread.new do
begin
# Do whatever
ensure
ActiveRecord::Base.connection_pool.release_connection
end
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With