Modifica principale: Da quando ho trovato questo problema, l'ho ridotto a un livello inferiore. Penso che questa sia ora una marginalmente descrizione più precisa del problema. I commenti sul PO potrebbero pertanto non essere interamente correlati.Errore di filettatura quando si utilizza `ActiveRecord with_connection do` e ActionController :: Live
Modifica versione leggermente modificata pubblicato in Rails/progetti puma: https://github.com/rails/rails/issues/21209, https://github.com/puma/puma/issues/758
Modifica Ora riprodotto con OS X e Rainbows
Sommario:Quando si utilizza Puma e correre lungo connessioni in esecuzione Sto ricevendo costantemente errori relativi alle connessioni ActiveRecord che attraversano i thread. Questo si manifesta in un messaggio comemessage type 0x## arrived from server while idle
e un server bloccato (arrestato).
Il set up:
- Ubuntu 15/OSX Yosemite
- PostgreSQL (9.4)/MySQL (
mysqld 5.6.25-0ubuntu0.15.04.1
) - Rubino - MRI
2.2.2p95 (2015-04-13 revision 50295) [x86_64-linux]
/Rubiniusrbx-2.5.8
- Rails (
4.2.3
,4.2.1
- Puma (
2.12.2
,2.11
) - pg (
pg-0.18.2
)/mysql2
nota, non tutte le combinazioni delle versioni di cui sopra sono state provate. La prima versione elencata è ciò che sto attualmente testando contro.
rails new issue-test
- Aggiungere un percorso
get 'events' => 'streaming#events'
- Aggiungere un controller
streaming_controller.rb
- Impostare roba database (
pool: 2
, ma visto con diverse dimensioni della piscina)
Codice:
class StreamingController < ApplicationController
include ActionController::Live
def events
begin
response.headers["Content-Type"] = "text/event-stream"
sse = SSE.new(response.stream)
sse.write({:data => 'starting'} , {:event => :version_heartbeat})
ActiveRecord::Base.connection_pool.release_connection
while true do
ActiveRecord::Base.connection_pool.with_connection do |conn|
ActiveRecord::Base.connection.query_cache.clear
logger.info 'START'
conn.execute 'SELECT pg_sleep(3)'
logger.info 'FINISH'
sse.write({:data => 'continuing'}, {:event => :version_heartbeat})
sleep 0.5
end
end
rescue IOError
rescue ClientDisconnected
ensure
logger.info 'Ensuring event stream is closed'
sse.close
end
render nothing: true
end
end
Configurazione
Puma:
workers 1
threads 2, 2
#...
bind "tcp://0.0.0.0:9292"
#...
activate_control_app
on_worker_boot do
require "active_record"
ActiveRecord::Base.connection.disconnect! rescue ActiveRecord::ConnectionNotEstablished
ActiveRecord::Base.establish_connection(YAML.load_file("#{app_dir}/config/database.yml")[rails_env])
end
- eseguire il server
puma -e production -C path/to/puma/config/production.rb
script di test:
#!/bin/bash
timeout 30 curl -vS http://0.0.0.0/events &
timeout 5 curl -vS http://0.0.0.0/events &
timeout 30 curl -vS http://0.0.0.0/events
Questo ragionevolmente risultati sempre in un blocco completo del server di applicazione (in PostgreSQL, vedere le note).Il messaggio viene da paura libpq
:
message type 0x44 arrived from server while idle
message type 0x43 arrived from server while idle
message type 0x5a arrived from server while idle
message type 0x54 arrived from server while idle
Nel 'mondo reale' Ho un paio di elementi abbastanza in più e il problema si presenta in modo casuale. La mia ricerca indica che questo messaggio proviene da libpq
ed è sottotesto per il problema di comunicazione ', eventualmente utilizzando la connessione in thread diversi'. Infine, durante la stesura di questo, ho avuto il blocco del server senza un singolo messaggio in qualsiasi registro.
Quindi, la domanda (s):
- è il modello che sto seguendo non è legale in qualche modo? Che cosa ho mis [sed | capito]?
- Che cos'è lo "standard" per lavorare con le connessioni di database qui che dovrebbe evitare questi problemi?
- Riesci a vedere un modo per riprodurlo in modo affidabile?
o
- Qual è il problema di fondo qui e come posso risolverlo?
MySQL
Se MySQL in esecuzione, il messaggio è un po 'diverso, e l'applicazione recupera (anche se non sono sicuro se è poi in qualche stato non definito):
F, [2015-07-30T14:12:07.078215 #15606] FATAL -- :
ActiveRecord::StatementInvalid (Mysql2::Error: This connection is in use by: #<Thread:[email protected]/home/dev/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/actionpack-4.2.3/lib/action_controller/metal/live.rb:269 sleep>: SELECT `tasks`.* FROM `tasks` ORDER BY `tasks`.`id` ASC LIMIT 1):
Da ActiveRecord, i documenti che utilizzano with_connection si basano sul blocco passato come argomento che termina. Sei sicuro che sia completo? Che ne dici di gestire la connessione con Base.connection o checkout? – Grasshopper
@Grasshopper - grazie! Sono preoccupato che ciò manterrà la connessione aperta per tutta la durata della richiesta (ore), in modo da mangiare il mio pool di connessioni abbastanza rapidamente? Suppongo che il modo in cui potrebbe non essere completato è se sse.write blocca per qualche motivo e il thread si trova lì, cioè se la connessione è andata e non ritorna per qualche motivo? (Detto questo, non sono sicuro che spieghi completamente i messaggi basati su problemi thread da libpq). (sperimenterà alcune cose in quella direzione) – button
In effetti il problema che descrivi può accadere in scenari in cui le connessioni non vengono rilasciate. Puoi provare a rimuovere la chiamata a sse.write dal blocco with_connection? – Grasshopper