我在Sidekiq的后台工作得到一个ActiveRecord::ConnectionTimeoutError: could not obtain a connection from the pool
例外
配置
-
我有一个PUMA web进程和一个SIDEKIQ进程运行在Heroku (2 hobby dynos) [Rails应用程序与后台作业]
-
在
database.yml
中我有pool: 40
(在default
和production
中) -
在
sidekiq.yml
我有:concurrency: 7
-
在
puma.rb
中,我有max_threads_count = ENV.fetch("PUMA_MAX_THREADS") { 5 }
并设置了ENV["PUMA_MAX_THREADS"] = 5
-
我正在使用一个Heroku pgsql业余爱好实例,它允许
20 connections
预期行为
当7个Sidekiq worker忙于运行作业时,它们应该有足够的可用db连接。
因为:
需要的数据库连接:
- 5 for 5 PUMA线程
- 12: [7 + 5] for SIDEKIQ threads (7 workers + 5 for redis?)-不确定背后的原因)
- 总需求:17 [12+5]
- 可用总数:20
实际行为
当7个Sidekiq工人忙于运行作业时,2个作业失败并引发ConnectionTimeOutError
(总是2个作业,因此实际最大并发数为5)
STUFF I observed (MIGHT HELP):
-
在SIDEKIQ仪表板中,Redis连接达到最大10(从未更高)[我猜5线程+ 5]
-
在Heroku db中,当大量作业排队时,连接数总是远低于可用的20个(所以pgsql实例没有问题)
任何帮助或建议将是超级感激:))
提前感谢!
更新:添加database.yml
文件
default: &default
adapter: postgresql
encoding: unicode
pool: <%= ENV.fetch("DB_POOL") { 10 } %>
development:
<<: *default
database: tracker_app_development
test:
<<: *default
database: tracker_app_test
production:
url: <%= ENV['DATABASE_URL'] %>
pool: <%= ENV.fetch("DB_POOL") { 10 } %>
web: DB_POOL=$PUMA_MAX_THREADS bundle exec puma -C config/puma.rb
worker: DB_POOL=14 bundle exec sidekiq -C config/sidekiq.yml
release: rake db:migrate
此异常是从Rails中的ActiveRecord::ConnectionAdapters::ConnectionPool::Queue
类引发的,特别是在该类的poll
方法中,该方法接受超时时间(默认为5s)。错误是这样被引发的:
if elapsed >= timeout
msg = "could not obtain a connection from the pool within %0.3f seconds (waited %0.3f seconds); all pooled connections were in use" %
[timeout, elapsed]
raise ConnectionTimeoutError, msg
end
我认为这是在说,如果从它尝试获得连接以来经过的时间大于提供的超时(默认为5s),那么它将引发此异常。发生这种情况是因为池中的可用连接数为10,而在Sidekiq中,您提到的默认池大小为14。尝试将web动态分析器的池大小增加到大于或等于Sidekiq动态分析器中指定的默认池连接数。
如果这不起作用,那么您可以尝试将checkout_timeout
从5s增加到更长的持续时间,如下所示:
default: &default
adapter: postgresql
encoding: unicode
pool: <%= ENV.fetch("DB_POOL") { 10 } %>
checkout_timeout: 10
development:
<<: *default
database: tracker_app_development
test:
<<: *default
database: tracker_app_test
production:
url: <%= ENV['DATABASE_URL'] %>
pool: <%= ENV.fetch("DB_POOL") { 10 } %>
这是Rails的API文档对ConnectionPools的解释
https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/ConnectionPool.html
解决方案发现:
在我的database.yml
文件中,production
配置有1个缩进,而它应该有0…