ruby - 西纳特拉、美洲狮、ActiveRecord : No connection pool with 'primary' found

标签 ruby activerecord database-connection sinatra puma

我正在使用 Ruby 2.4.4、Sinatra 2.0.5、ActiveRecord 5.2.2、Puma 3.12.0 构建服务。 (我没有使用导轨。)

我的代码如下所示。我有一个打开数据库连接(到 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'
...

到目前为止,我的发现过程是这样进行的。

  1. 我查看了 Postgres 中的连接使用情况,认为我可能会泄漏连接 - 不,我似乎没有。
  2. 以防万一,我将连接池增加到 16(对应于 16 个 Puma 线程)- 没有帮助。
  3. 然后我查看了 ActiveRecord 源代码。在这里我意识到为什么 2) 没有帮助。问题不是我无法获得连接,而是我无法获得连接池(是的,是的,它在异常中说了)。 @owner_to_pool 映射变量,从中获取连接池,将process_id存储为键,并作为值-连接池(实际上,值也是一个映射,其中键是连接规范,我认为值是实际的池实例)。就我而言,我只有一个连接规范到我唯一的数据库。

    但是 Puma 是一个多线程网络服务器。它在同一进程但在不同线程中运行所有请求。

    正因为如此,我认为会发生以下情况:

    • 第一个请求,从process_id=X开始,thread=Y,“ checkout ”establish_connection中的连接池,基于process_id=X, - 并“接受”它。现在它不在 @owner_to_pool 中。
    • 第二个请求,从相同的 process_id=X 开始,但不同的 thread=Z,尝试执行相同的操作 - 但 process_id 的连接池=X 不在 owner_to_pool 中。因此第二个请求没有获得连接池并因该异常而失败。
    • 第一个请求成功完成,并通过调用 clear_all_connectionsprocess_id=X 的连接池放回原位。
    • 另一个请求,在这之后开始,并且在并行线程中没有任何并行请求,将会成功,因为它会获取连接池并毫无问题地再次放回去。

虽然我不确定我是否 100% 正确地理解了所有内容,但在我看来,这样的事情确实会发生。

现在,我的问题是:我该如何处理这一切? 如何使多线程 Puma 网络服务器与 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

关于ruby - 西纳特拉、美洲狮、ActiveRecord : No connection pool with 'primary' found,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54158828/

相关文章:

postgresql - psql : FATAL: role "postgres" does not exist (with -h localhost option)

php - 我保护 MySQL 数据库密码的方法安全吗?

Tomcat 在数据库重启时不重新连接 PostgreSQL JDBC 池

ruby-on-rails - 在 jruby 上安装 gem

mysql - 如何访问mysql表字段模式描述列?

ruby-on-rails - Rails ActiveRecord 保存错误未定义方法 `[]' for nil :NilClass

ruby-on-rails - Rails 3 忽略 Postgres 唯一约束异常

ruby - 选择一个随机选项,其中每个选项被选中的概率不同

ruby-on-rails - 如何找到声明 ruby​​ 方法的位置?

ruby - 带有通配符的正则表达式否定回顾