33

Büyük/küçük resim: Bu düzenlemeyi düşündüğümüzden beri aşağıdan aşağıya doğru sürükledim. Bence bu şimdi bir marjinal sorunun daha kesin bir açıklaması. OP ile ilgili yorumlar bu nedenle tamamen korelasyon gösteremez. raylar/puma projelerinde yayınlanmıştır`ActiveRecord with_connection do` & ActionController :: Live

Düzenleme hafifçe değiştirilmiş versiyonu: https://github.com/rails/rails/issues/21209, https://github.com/puma/puma/issues/758

Düzenleme Şimdi OS X ve Rainbows

Özeti ile çoğaltılabilir:Puma kullanarak ve koşu uzun bağlantıları çalıştırarak sürekli olarak ActiveRecord bağlantıları geçiş konularıyla ilgili hatalar alıyorum. Bu, kendisinimessage type 0x## arrived from server while idleve kilitli (çökmüş) bir sunucuda gösterir.

kurmak:

  • Ubuntu 15/OSX Yosemite
  • PostgreSQL (9.4)/MySQL (mysqld 5.6.25-0ubuntu0.15.04.1)
  • Yakut - MRG 2.2.2p95 (2015-04-13 revision 50295) [x86_64-linux]/Rubinius rbx-2.5.8
  • Raylar (4.2.3, 4.2.1)
  • Puma (2.12.2, 2.11)
  • pg (pg-0.18.2)/mysql2

Not Yukarıdaki sürümleri tüm kombinasyonları denenmiştir. İlk listelenen sürüm şu anda test ettiğim şey.

  • rails new issue-test
  • ekle bir denetleyici bir rota get 'events' => 'streaming#events'
  • ekle streaming_controller.rb
  • ayarlama veritabanı şeyler (pool: 2, ancak farklı havuz boyutları ile görülen)

Kodu:

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 

Puma yapılandırma:

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 
  • Run sunucusu puma -e production -C path/to/puma/config/production.rb

Testi komut:

#!/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 

Bu makul tutarlı PostgreSQL (uygulama sunucusu tam bir kilit ile sonuçlanır Notları görmek).Epeyce ekstra unsurlar var 'gerçek-dünya' olarak

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 

ve sorunun rastgele kendini göstermektedir: korkutucu mesaj libpq geliyor. Araştırmam bu mesajın libpq'dan geldiğini ve 'iletişim sorununun alt metni olduğunu, muhtemelen' farklı konularda bağlantı kullanarak gösteriyor. Sonunda, bu yazılırken, herhangi bir günlüğünde tek bir mesaj olmadan sunucuyu kilitledim.

Yani, soru (lar):

  1. Bir şekilde yasal olmayan takip ediyorum desen var mı? Benim neyim var [sed | understood]?
  2. Burada veritabanı bağlantılarıyla çalışmak için 'standart' bu sorunlardan kaçınılması gereken nedir?
  3. Bunu güvenilir bir şekilde yeniden üretmenin bir yolunu görebiliyor musunuz?

veya

  1. Burada altta yatan bir konudur ve bunu nasıl çözebilir?

MySQL

MySQL çalışan, ileti biraz farklıdır ve (yine de biraz tanımlanmamış durumda sonra ise emin değilim gerçi) uygulaması kurtarır:

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): 
+1

with_connection işlevini kullanarak ActiveRecord belgelerinden, bağımsız değişken tamamlandı olarak iletilen bloğa güvenir. Tamamladığından emin misin? Base.connection veya checkout ile bağlantıya ne dersin? – Grasshopper

+1

@Grasshopper - teşekkürler! Bunun, bağlantının (saat) kullanım ömrü boyunca açık bir şekilde bağlantı kurmasını ve böylece bağlantı havuzumu oldukça hızlı bir şekilde yiyeceğinden endişeleniyorum. Sanırım tamamlanmama yolu, eğer bir nedenden ötürü sse.write bloklar varsa ve iş parçacığı sadece orada oturursa, yani eğer bağlantı gitti ve bir sebepten ötürü geri dönmezse? (Bu, libpq'den gelen thread-problem tabanlı mesajları tam olarak açıkladığından emin değilim). (Bu yönde birkaç şeyle deney yapacağız) – button

+1

Açıkladığınız sorun, bağlantıların serbest bırakılmadığı senaryolarda gerçekleşebilir. Aramayı with_connection bloğundan sse.write'e kaldırabilir misiniz? – Grasshopper

cevap

1

Uyarı:

'fark yaratmak gibi görünüyor' olarak okunur 'cevabı'

begin 
    #... 
    while true do 
    t = Thread.new do #<<<<<<<<<<<<<<<<< 
     ActiveRecord::Base.connection_pool.with_connection do |conn| 
      #... 
     end 
    end 
    t.join #<<<<<<<<<<<<<<<<< 
    end 
    #... 
rescue IOError 
#... 

Ama bu aslında sorun çözülmüş ya da sadece son derece olası yapıp yapmadığını bilmiyorum:


ben gibi görünmek için denetleyici bloğu değiştirirseniz sorun ortaya görmüyorum. Bunun neden bir fark yaratacağını gerçekten de anlamam.

Bu, bir çözüm olarak yorumlanması durumunda yardımcı olur, ancak yine de sorun üzerinde kazma.

+0

Bu yüzden uzun bir koşu sürecim var ve ben de böyle kullanıyorum. Benim sorum, neden her yineleme için bir iş parçacığı başlatıyorsunuz? iş parçacığı başlatmak ve her bir istemci için bağlantıyı devre dışı bırakmak mantıklı değil mi? –