ActiveRecord::ConnectionTimeoutError

8

我遇到了这个错误:

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

首先我遇到了这个错误,将计数从5增加到16。但问题仍然存在,而且我是唯一测试数据库的人。既然我是唯一的用户,为什么会发生这种情况?

顺便说一下,我没有使用Rails。 我正在使用:

ActiveRecord::Base.establish_connection ({
    :adapter => 'mysql2',
    :database => 'ck',
    :host => 'localhost',
    :username => 'root',
    :password => '',
    :pool => 16,
    })

并且使用Sinatra。谢谢。
4个回答

12

正如Frederick所指出的那样,您需要将打开的ActiveRecord连接返回到连接池中。

如果您正在使用线程模式的Thin服务器,则需要将以下内容添加到Sinatra应用程序中:

after do
  ActiveRecord::Base.connection.close
end

相比使用ConnectionManagement建议,更好的选择是避免它。原因是Thin将请求处理分成了2个线程,关闭ActiveRecord连接的线程与打开它的线程不同。由于ActiveRecord通过线程ID跟踪连接,它会混淆并无法正确地返回连接。


@squixy - 把这个放在你的应用程序中任何一个继承 Sinatra::Base 的类里。 - Ramfjord
3
你为什么在使用ActiveRecord::Base.connection.close而不是文档中指定的ActiveRecord::Base.clear_active_connections!?这是因为文档已经过时了吗? - Ramfjord

5
看起来你没有在请求结束时将连接返回到池中。如果没有这样做,那么每个使用数据库的请求都会消耗1个连接,最终你会耗尽池并开始收到你描述的错误信息。
Active Record提供了一个Rack中间件来处理这个问题 ActiveRecord::ConnectionAdapters::ConnectionManagement ,只要它位于访问Active Record的任何中间件链之前,就应该可以解决问题。
你也可以自己处理连接管理。docs中有更多细节,但一种方法是将所有db访问都放在这样的块中。
ActiveRecord::Base.connection_pool.with_connection do
  ...
end

在块的开始处检查连接,并在之后将其归还。


谢谢。我应该在 ActiveRecord::Base.establish_connection 之前调用这个吗? - 0xSina
这是我在脚本中调用的第一个函数,但仍然出现相同的错误 :( - 0xSina
“Calling it” 是什么意思?你是将它添加到中间件堆栈中吗?(如果我没记错的话,Sinatra 文档有示例) - Frederick Cheung

1

最好使用ActiveRecord提供的中间件

use ActiveRecord::ConnectionAdapters::ConnectionManagement

0
正如Frederick所指出的那样,您需要将打开的ActiveRecord连接返回到连接池中。
正如kuwerty所建议的那样,当您使用Thin时,ConnectionManagement不会将连接返回到池中。我建议您不要像kuwerty说的那样关闭当前连接,而是将连接返回到池中,就像这样。
after do
  ActiveRecord::Base.clear_active_connections!
end

对于那些想要重现问题的人,请尝试 这个例子

编辑:

我解释了为什么在 Thin 多线程模式下使用中间件 ActiveRecord::Connectionadapters::ConnectionManagement 无法正常工作,你可以在这里找到。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接