1

我有一个 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'
4

2 回答 2

1

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

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

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

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

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

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

于 2021-03-03T07:50:38.270 回答
1

我遇到了同样的问题,要解决它只是增加数量或threads在配置中,我使用预加载的 32 和 0 个工人(实际上是一个但不是在集群模式下,如果我使用工人 1 将启用)

简而言之,你需要这个

workers 0   
threads 32, 32

我的自定义机架应用程序的完整 puma 配置

# set app root
Dir.chdir File.expand_path("../..", __FILE__)

# load RACK_ENV
require 'dotenv'
Dotenv.load

require 'bundler/setup'
Bundler.require

plugin          :tmp_restart
port            3000
log_requests    false
nakayoshi_fork  true
pidfile         './tmp/puma.pid'
state_path      './tmp/puma.state'

# activate_control_app('tcp://127.0.0.1:9000', no_token: true)

if ENV['RACK_ENV'] == 'production'
  stdout_redirect './log/puma.log', './log/puma_errros.log'
  environment 'production'
  workers     0
  threads     32, 32

  # restart if there is no response on /ok, check every 10 seconds
  Thread.new do
    loop do
      sleep 10

      unless `curl -si -m 5 http://localhost:3000/ok`.include?('200 OK')
        Logger.new('log/app_boot.log').error 'http://localhost:3000/ok fail, restarting'
        `touch tmp/restart.txt`
      end
    end
  end
end

于 2022-01-16T18:10:31.223 回答