Как управлять открытием и закрытием соединений с базой данных при работе с activerecords и несколькими потоками

Я пытаюсь реализовать многопоточный метод в рельсах, чтобы очень быстро создавать/обновлять несколько записей.

Это контур моей программы.

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

Это дает мне предупреждения в моем журнале.

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.

И это дает мне ошибку

could not obtain a database connection within 5 seconds (waited 5.059358 seconds). 
The max pool size is currently 5; consider increasing it.

Я попробовал:  - изменение database.yaml и увеличение пула и тайм-аута.  - изменил существующий код следующим образом.

   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

Я все еще получаю то же предупреждение и ошибку. Я, очевидно, пропустил концепцию здесь. Как это сделать?

Ответ 1

Чтобы предотвратить утечку соединения в нескольких потоках, вам необходимо управлять соединением вручную. Вы можете попробовать:

Thread.new do
  ActiveRecord::Base.connection_pool.with_connection do
    # Do whatever
  end
end

Одна из проблем ActiveRecord::Base.connection_pool.with_connection заключается в том, что она всегда готовит соединение, даже если код внутри не нуждается.

Мы можем немного улучшить его, используя ActiveRecord::Base.connection_pool.release_connection:

Thread.new do
  begin
    # Do whatever
  ensure
    ActiveRecord::Base.connection_pool.release_connection
  end
end

Ответ 2

если вы хотите запускать N потоков, убедитесь, что у вас есть N соединений в пуле

#  ActiveRecord::Base.connection_config
#  # => {pool: 5, timeout: 5000, database: "db/development.sqlite3", adapter: "sqlite3"}

в противном случае вы сможете получить соединение из пула.