我遇到了Sidekiq工人的问题。
ActiveRecord::ConnectionTimeoutError: could not obtain a database connection within 5.000 seconds (waited 5.000 seconds)
我正在遵循有关使用ActiveRecord::ConnectionTimeoutError
和适当大型连接池的建议。
我想知道我是否在耗尽连接池。我正在从size
中记录connections.length
和ActiveRecord::Base.connection_pool
,但它们保持不变的大小= 100 connections.length = 5.这表明这不是资源泄漏问题。< / p>
我的MySQL服务器配置为允许最多400个并发连接。
我的工作最终看起来像这样:
class MyJob < ActiveJob::Base
queue_as :default
rescue_from StandardError do |exception|
# clear connections on exception. Not sure if this is a good idea or not.
ActiveRecord::Base.clear_active_connections!
end
def perform()
logger.info "size"
logger.info ActiveRecord::Base.connection_pool.instance_eval { @size }
logger.info "connections"
logger.info ActiveRecord::Base.connection_pool.instance_eval { @connections }.length
# Ensure connections come from connection pool.
ActiveRecord::Base.connection_pool.with_connection do |conn|
# do stuff
end
end
end
这是诊断造成这种情况的正确方法,无论是资源匮乏还是泄漏?是否有其他技术可以解决为什么会发生这种情况?
答案 0 :(得分:2)
在我看来,这个ActiveRecord::ConnectionTimeoutError
只能出现在一个场景中 - 当那么多想要使用数据库连接的线程时,池已经耗尽,甚至等待免费连接没有帮助(从source code中学到的)。
在你的情况下,这很奇怪。您只使用25个工作线程,但池设置为100个连接,因此有足够的保留。我仍然怀疑你必须在某个地方产生线程。也许你在工作中做一些线程?也许你使用一个在你的工作中创建线程的gem?
无论如何,如果你能够重现异常,我建议抓住它并获取所有线程发生时的列表,如下所示:
begin
# job stuff...
rescue ActiveRecord::ConnectionTimeoutError
puts "listing #{Thread.list.count} threads:"
Thread.list.each_with_index do |t,i|
puts "---- thread #{i}: #{t.inspect}"
puts t.backtrace.take(5)
end
end
我预计会有100个或更多线程,你应该看看它们在回溯中究竟是哪个。
答案 1 :(得分:0)
尝试ActiveRecord::ConnectionAdapters::ConnectionPool#stat
ActiveRecord::Base.connection_pool.stat
# => { size: 15, connections: 1, busy: 1, dead: 0, idle: 0, waiting: 0, checkout_timeout: 5 }
从connection_adapters/abstract/connection_pool.rb
开始,处于有效记录5.2.2.2.1。