Heroku + Sidekiq: ActiveRecord:: StatementInvalid: PG:: UnableToSend: SSL SYSCALL error: EOF detected

Salut nous courons sur la pile de cèdre D'Heroku avec Unicorn et Sidekiq. Nous obtenons par intermittence les erreurs suivantes

BurnThis ActiveRecord::StatementInvalid: PG::UnableToSend: SSL SYSCALL error: EOF detected

ActiveRecord::StatementInvalid: PG::ConnectionBad: PQconsumeInput() SSL SYSCALL error: Connection timed out

quelqu'un a une aperçu de ce que la cause directe de ces erreurs? Est-ce trop de connexions à notre base de données? Nous avons déjà installé notre fourche de la manière suivante:

licorne.rb

worker_processes Integer(ENV["WEB_CONCURRENCY"] || 3)
timeout 30
preload_app true

before_fork do |server, worker|
  Signal.trap 'TERM' do
    puts 'Unicorn master intercepting TERM and sending myself QUIT instead'
    Process.kill 'QUIT', Process.pid
  end

  defined?(ActiveRecord::Base) and
    ActiveRecord::

Base.connection.disconnect!
end

after_fork do |server, worker|
  Signal.trap 'TERM' do
    puts 'Unicorn worker intercepting TERM and doing nothing. Wait for master to send QUIT'
  end

  # other setup
  if defined?(ActiveRecord::Base)
    config = Rails.application.config.database_configuration[Rails.env]
    config['adapter'] = 'postgis'
    config['pool']              = ENV['DB_POOL'] || 5
    config['reaping_frequency'] = ENV['DB_REAP_FREQ'] || 10 # seconds
    ActiveRecord::Base.establish_connection(config)
  end
end

et sidekiq.rb

Sidekiq.configure_server do |config|
  config.redis = { :url => ENV['REDIS_URL'], :namespace => 'btsidekiq' }

  if defined?(ActiveRecord::Base)
    config = Rails.application.config.database_configuration[Rails.env]
    config['adapter'] = 'postgis'
    config['pool']              = ENV['DB_POOL'] || 5
    config['reaping_frequency'] = ENV['DB_REAP_FREQ'] || 10 # seconds
    ActiveRecord::Base.establish_connection(config)
  end
end

Sidekiq.configure_client do |config|
  config.redis = { :url => ENV['REDIS_URL'], :namespace => 'btsidekiq' }
end

LA TAILLE DE NOTRE pool de base de données est assez grande DB_POOL=100 et nous sommes sur une base de données PG qui apparemment, il supporte 500 connexions simultanément.

18
demandé sur Chris Travers 2013-11-06 05:11:29

1 réponses

Cette erreur est causée par votre postgis adaptateur essayant d'utiliser une connexion viciée/morte à partir du pool de connexion ActiveRecord. Il y a deux façons d'aborder cette question:

  1. Taille de votre pool de connexion pour correspondre au nombre de threads/processus
  2. basse fréquence de récolte des connexions (Reaper vérifie les connexions mortes, toutes les N secondes)

pour mettre en œuvre #1, vous avez besoin de définir la taille de votre piscine appropriée pour Unicorn et Sidekiq, qui ils ont probablement des besoins différents.

Unicorn est simple threaded, donc la taille de pool par défaut de 5 les connexions par processus sont correctes pour vous. Cela va affecter jusqu'à 5 connexions pour chaque WEB_CONCURRENCY backend licorne travailleurs. Vous devez réinitialiser la taille de la piscine par défaut et utiliser votre unicorn.rb:

$> heroku config:set DB_POOL=5

Sidekiq utilise cependant un modèle très différent. Par défaut, Sidekiq dispose d'un seul processus et de N threads. Vous voulez une taille de piscine DB légèrement plus grande que le nombre de fils de Sidekiq. Vous pouvez implémenter ceci dans votre config/initializers/sidekiq.rb comme suit:

Sidekiq.configure_server do |config|
  pool_size = Sidekiq.options[:concurrency] + 2

  config.redis = { :url => ENV['REDIS_URL'], :namespace => 'btsidekiq', :size => pool_size }

  if defined?(ActiveRecord::Base)
    config = Rails.application.config.database_configuration[Rails.env]
    config['adapter'] = 'postgis'
    config['pool']              = pool_size
    config['reaping_frequency'] = ENV['DB_REAP_FREQ'] || 10 # seconds
    ActiveRecord::Base.establish_connection(config)
  end
end

Ma meilleure supposition est qu'en utilisant un si grand pool de 100 connexions, vous êtes plus susceptible d'accumuler des connexions mortes. Le dimensionnement de la piscine devrait corriger cela.

Si cela ne fonctionne pas, vous devriez essayer de réduire votre DB_REAP_FREQ à 5 secondes.

4
répondu Winfield 2014-03-12 15:39:56