2016-12-19 1 views
2

Le médiateur Rack et la file d'attente de requêtes Heroku augmentent parfois dans mon application Ruby/Sinatra, ce qui provoque le blocage de l'application jusqu'à ce que je redémarre manuellement les serveurs. J'ai fait des réglages sur le Rack :: Timeout, Postgres Timeout, et mis à jour les appels Postgres afin qu'ils fonctionnent pour la plupart sous 100ms. En règle générale, lorsque la file d'attente de requêtes augmente, les serveurs redémarrent automatiquement et continuent sans problème, mais lorsque l'intergiciel augmente, l'application ne parvient pas à se rétablir et l'application reste bloquée dans la file d'attente. Qu'est-ce qui cause cela?Qu'est-ce qui provoque le pic de mon middleware Rack?

Voici une capture d'écran de New Relic montrant la pointe dans Middleware:

New Relic chart showing time spent in Request Queuing increase to 20s, Middleware increase to 40s, and Ruby increase to 14s, then crashing. After that, time spent in Request Queue is always 20s

Et voici les fichiers où je définir les connexions middleware et base de données:

config/puma.rb

threads_count = Integer(5) 
threads threads_count, threads_count 

preload_app! 

rackup  DefaultRackup 
port  ENV['PORT']  || 3000 
environment ENV['RACK_ENV'] || 'development' 

on_worker_boot do 
    ActiveSupport.on_load(:active_record) do 
     db = URI.parse(ENV['DATABASE_URL']) 
     ActiveRecord::Base.establish_connection(
      :adapter => db.scheme == 'postgres' ? 'postgresql' : db.scheme, 
      :host  => db.host, 
      :username => db.user, 
      :password => db.password, 
      :database => db.path[1..-1], 
      :port => db.port, 
      :encoding => 'utf8', 
      :reaping_frequency => 10 
      :pool => 5 
      :timeout => 11 
     ) 
    end 
end 

config.ru

require "rack-timeout" 
use Rack::Timeout, service_timeout: 16, wait_timeout: 23 

require './web' 

run Sinatra::Application 
use ActiveRecord::ConnectionAdapters::ConnectionManagement 

rakefile.rb

require "./web" 
require "sinatra/activerecord/rake" 

Gemfile

source 'https://rubygems.org' 
ruby '2.3.1' 
gem 'rack-timeout' 
gem 'rake' 
gem 'sinatra' 
gem 'puma', "~> 2.16.0" 
gem 'pg' 
gem "activerecord", "< 5.0.0" # h/t https://github.com/janko-m/sinatra-activerecord/pull/66 
gem 'activesupport' 
gem 'sinatra-activerecord' 
gem 'redis' 
gem 'tilt' 

fichier journal à partir d'un moment où l'application est écrasé

app/web.2: Rack app error: #<Rack::Timeout::RequestTimeoutError: Request waited 783ms, then ran for longer than 15000ms> 
app/web.2: /app/vendor/bundle/ruby/2.3.0/gems/activerecord-4.2.7.1/lib/active_record/connection_adapters/postgresql/database_statements.rb:155:in `async_exec' 
app/web.2: #<Rack::Timeout::RequestExpiryError: Request older than 30000ms.> 

Logfile supplémentaires avec l'erreur qui se produit de temps en temps avant se bloque l'application

app/web.2: /app/vendor/ruby-2.3.1/lib/ruby/2.3.0/monitor.rb:187:in `lock', deadlock; recursive locking 
+0

FYI - lorsque j'ai mis à jour ma base de données à [standard-2] (https://devcenter.heroku.com/articles/heroku-postgres-plans), ce problème est parti. –

Répondre

1

basé sur cette ligne de l'erreur de délai d'attente backtrace:

/app/vendor/bundle/ruby/2.3.0/gems/activerecord-4.2.7.1/lib/active_record/connection_adapters/postgresql/database_statements.rb:155:in `async_exec' 

Il semblerait que, au moment de la demande a été expiré de force (Rack :: Timeout) que l'enregistrement actif était au milieu de cet appel async_exec à votre base de données.

Sur la base de l'autre erreur que vous avez posté:

/app/vendor/ruby-2.3.1/lib/ruby/2.3.0/monitor.rb:187:in `lock', deadlock; recursive locking 

Je dirais qu'il est évident que l'adaptateur de connexion postgres rencontré une impasse.

Il n'est pas apparent si l'interblocage se produit dans postgres et bullage jusqu'à enregistrement actif ou si le blocage se produit dans le code de l'adaptateur de connexion. Avez-vous des requêtes lentes enregistrées dans postgres? L'erreur de blocage peut être simplement symptom of using Rack::Timeout (or just the Timeout ruby class) while using threads. Il se peut qu'un thread ait atteint un délai d'expiration en raison d'une requête lente, que Timeout :: Error ait été déclenché et que la connexion/mutex dans la gestion des connexions devienne instable/mal gérée.