Sinatra,Puma,ActiveRecord:没有找到“主要”的连接池
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Sinatra,Puma,ActiveRecord:没有找到“主要”的连接池相关的知识,希望对你有一定的参考价值。
我正在使用Sinatra 2.0.5,ActiveRecord 5.2.2,Puma 3.12.0在Ruby 2.4.4中构建服务。 (我不使用rails。)
我的代码看起来像这样。我有一个端点打开数据库连接(到Postgres数据库)并运行一些数据库查询,如下所示:
POST '/endpoint' do
# open a connection
ActiveRecord::Base.establish_connection(@@db_configuration)
# run some queries
db_value = TableModel.find_by(xx: yy)
return whatever
end
after do
# after the endpoint finishes, close all open connections
ActiveRecord::Base.clear_all_connections!
end
当我收到两个到此端点的并行请求时,其中一个请求失败并出现此错误:
2019-01-12 00:22:07 - ActiveRecord::ConnectionNotEstablished - No connection pool with 'primary' found.:
C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/activerecord-5.2.2/lib/active_record/connection_adapters/abstract/connection_pool.rb:1009:in `retrieve_connection'
C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/activerecord-5.2.2/lib/active_record/connection_handling.rb:118:in `retrieve_connection'
C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/activerecord-5.2.2/lib/active_record/connection_handling.rb:90:in `connection'
C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/activerecord-5.2.2/lib/active_record/core.rb:207:in `find_by'
...
到目前为止,我的发现过程一直如此。
- 我查看了Postgres中的连接用法,认为我可能会泄漏连接 - 不,我似乎没有。
- 为了以防万一,我将连接池增加到16(对应16个Puma线程) - 没有帮助。
- 然后我查看了ActiveRecord源代码。在这里,我意识到为什么2)没有帮助。问题不在于我无法获得连接,但我无法获得连接池(是的,是的,它在异常中表示)。从中获取连接池的
@owner_to_pool
映射变量将process_id
存储为键,并将值存储为连接池(实际上,该值也是一个映射,其中键是连接规范,我认为该值是一个实际的池实例)。在我的情况下,我只有一个连接规范到我唯一的数据库。 但Puma是一个多线程的网络服务器。它在同一进程中运行所有请求但在不同的线程中运行。 因此,我认为,会发生以下情况: 第一个请求,从process_id=X
,thread=Y
开始,根据establish_connection
“检查”process_id=X
中的连接池,并“接受”它。现在它不存在于@owner_to_pool
。 第二个请求,从相同的process_id=X
开始,但不同的thread=Z
,尝试做同样的事情 - 但process_id=X
中没有owner_to_pool
的连接池。因此,第二个请求不会获得连接池,并且会因该异常而失败。 第一个请求成功完成,并通过调用process_id=X
将clear_all_connections
的连接池放回原位。 另一个请求,从所有这些开始,并没有并行线程中的任何并行请求,将成功,因为它将获取连接池并将其重新放回,没有任何问题。
虽然我不确定我是否100%正确理解所有内容,但在我看来,这样的事情发生了。
现在,我的问题是:我怎么办这一切?如何使多线程Puma Web服务器与ActiveRecord连接池一起正常工作?
非常感谢提前!
This question看起来很相似,但遗憾的是它没有答案,我没有足够的声誉来评论它,并询问作者是否解决了它。
答案
所以,基本上,我没有意识到我是establish_connection
正在创建一个连接池。 (是的,是的,我在问题中这么说。但是,我还没有意识到这一点。)
我最终做的是这样的:
require ....
# create the connection pool with the required configuration - once; it'll belong to the process
ActiveRecord::Base.establish_connection(db_configuration)
at_exit {
# close all connections on app exit
ActiveRecord::Base.clear_all_connections!
}
class SomeClass < Sinatra::Base
POST '/endpoint' do
# run some queries - they'll automatically use a connection from the pool
db_value = TableModel.find_by(xx: yy)
return whatever
end
end
以上是关于Sinatra,Puma,ActiveRecord:没有找到“主要”的连接池的主要内容,如果未能解决你的问题,请参考以下文章
Sinatra 应用程序中的“Rake 无法加载此类文件”错误
将 Sinatra 与acts_as_audited 一起使用的任何示例?
在一个进程多个数据库连接 sinatra 应用程序中使用啥 ORM?