首页 > 解决方案 > 在 puma 工作人员处发生 Sequel::DatabaseDisconnectError,即使 db 在 puma 的 before_fork-hook 中已断开连接

问题描述

我有一个 hanami 1.3 应用程序,但问题应该与 hanami 无关。我想用普通的 Sequel-gem 连接到第二个数据库。因此,我在 hanami's 中定义了连接config/environment.rb

# config/environment.rb
# ...
DWH = Sequel.connect(ENV['DWH'], :loggers => [Logger.new($stdout)])
#...

在生产中,我有一个这样的 puma-config:

# config/puma.rb
require_relative './environment'
workers 5

threads_count = 1
threads threads_count, threads_count

daemonize true

preload_app!

rackup      DefaultRackup
port        2300
environment 'production'

before_fork do
  DWH.disconnect
end

on_worker_boot do
  Hanami.boot
end

我用before_fork钩子断开了数据库(http://sequel.jeremyevans.net/rdoc/files/doc/fork_safety_rdoc.html)。但过了一段时间我得到这样的错误:

Sequel::DatabaseDisconnectError: PG::UnableToSend: SSL SYSCALL error: EOF detected
    /home/usr/vendor/bundle/ruby/2.6.0/gems/sequel-4.49.0/lib/sequel/adapters/postgres.rb:166:in `async_exec'
    /home/usr/vendor/bundle/ruby/2.6.0/gems/sequel-4.49.0/lib/sequel/adapters/postgres.rb:166:in `block in execute_query'
    /home/usr/vendor/bundle/ruby/2.6.0/gems/sequel-4.49.0/lib/sequel/database/logging.rb:49:in `log_connection_yield'
    /home/usr/vendor/bundle/ruby/2.6.0/gems/sequel-4.49.0/lib/sequel/adapters/postgres.rb:166:in `execute_query'
    /home/usr/vendor/bundle/ruby/2.6.0/gems/sequel-4.49.0/lib/sequel/adapters/postgres.rb:153:in `block in execute'
    /home/usr/vendor/bundle/ruby/2.6.0/gems/sequel-4.49.0/lib/sequel/adapters/postgres.rb:129:in `check_disconnect_errors'
    /home/usr/vendor/bundle/ruby/2.6.0/gems/sequel-4.49.0/lib/sequel/adapters/postgres.rb:153:in `execute'
    /home/usr/vendor/bundle/ruby/2.6.0/gems/sequel-4.49.0/lib/sequel/adapters/postgres.rb:515:in `_execute'
    /home/usr/vendor/bundle/ruby/2.6.0/gems/sequel-4.49.0/lib/sequel/adapters/postgres.rb:327:in `block (2 levels) in execute'
    /home/usr/vendor/bundle/ruby/2.6.0/gems/sequel-4.49.0/lib/sequel/adapters/postgres.rb:537:in `check_database_errors'
    /home/usr/vendor/bundle/ruby/2.6.0/gems/sequel-4.49.0/lib/sequel/adapters/postgres.rb:327:in `block in execute'
    /home/usr/vendor/bundle/ruby/2.6.0/gems/sequel-4.49.0/lib/sequel/database/connecting.rb:301:in `block in synchronize'
    /home/usr/vendor/bundle/ruby/2.6.0/gems/sequel-4.49.0/lib/sequel/connection_pool/threaded.rb:107:in `hold'
    /home/usr/vendor/bundle/ruby/2.6.0/gems/sequel-4.49.0/lib/sequel/database/connecting.rb:301:in `synchronize'
    /home/usr/vendor/bundle/ruby/2.6.0/gems/sequel-4.49.0/lib/sequel/adapters/postgres.rb:327:in `execute'
    /home/usr/vendor/bundle/ruby/2.6.0/gems/sequel-4.49.0/lib/sequel/dataset/actions.rb:1135:in `execute'
    /home/usr/vendor/bundle/ruby/2.6.0/gems/sequel-4.49.0/lib/sequel/adapters/postgres.rb:680:in `fetch_rows'
    /home/usr/vendor/bundle/ruby/2.6.0/gems/sequel-4.49.0/lib/sequel/dataset/actions.rb:155:in `each'
  /home/usr/app/lib/repositories/dwh_repository.rb:39:in `to_a'

标签: rubypumasequelhanami

解决方案


我与 Sequel 的作者进行了交谈。看来,puma 配置和连接方法是正确的。

似乎,数据库连接被另一个网络部分(即 tcp 超时、防火墙......)丢弃了。

在这种情况下,这是 Sequel 的预期行为:

应用程序失去与数据库的连接。发生这种情况时,会引发 DatabaseDisconnectError 并且 Sequel 从连接池中删除连接。将根据需要创建新连接,直到最大池大小。

解决此问题的最佳方法是修复连接断开的原因(更改设置 [DB,服务器])。一个务实的解决方案可能是将数据库和应用程序放在同一台服务器上。

如果这是不可能的,有一个续集扩展,这可能是一种解决方法: https ://sequel.jeremyevans.net/rdoc-plugins/files/lib/sequel/extensions/connection_validator_rb.html


推荐阅读