Multithreading in Rails: Zirkuläre Abhängigkeit erkannt wird, während autoloading Konstante

Ich habe eine Rails-app, in der ich ein Rake-task, die multithreading verwendet Funktionen bereitgestellt, die von der Auger-ruby-gem.

Von Zeit zu Zeit begegne ich Circular dependency detected while autoloading constant Fehler.

Nach Googeln ein bisschen, ich fand, dass dies im Zusammenhang mit Verwendung von threading in Kombination mit einer lade-Schienen-Konstanten.

Stolperte ich über die folgenden GitHub-Fragen: https://github.com/ruby-concurrency/concurrent-ruby/issues/585 und https://github.com/rails/rails/issues/26847

Wie hier beschrieben müssen Sie wickeln Sie jeden code, der aufgerufen wird, von einem neuen thread in einem Rails.application.reloader.wrap do oder Rails.application.executor.wrap do block, das ist, was ich Tat. Dies führt jedoch in die Sackgasse.

Empfehlung ist dann zu verwenden ActiveSupport::Dependencies.interlock.permit_concurrent_loads zu wickeln ein weiterer blockierender Aufruf im Haupt-thread. Allerdings bin ich unsicher, welchen code sollte ich wickeln, diese mit.

Hier ist, was ich versucht, aber dies führt noch zu einem deadlock:

@beanstalk = Beaneater.new("#{ENV.fetch("HOST", "host")}:#{ENV.fetch("BEANSTALK_PORT", "11300")}")
tube_name = ENV.fetch("BEANSTALK_QUEUE_NAME", "queue")

pool = Concurrent::FixedThreadPool.new(Concurrent.processor_count * 2)

# Process jobs from tube, the body of this block gets executed on each message received
@beanstalk.jobs.register(tube_name) do |job|
    ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
      @logger.info "Received job: #{job.id}"
      Concurrent::Future.execute(executor: pool) do
        Rails.application.reloader.wrap do
          # Stuff that references Rails constants etc
          process_beanstalk_message(job.body)
        end
      end
    end
end

@beanstalk.jobs.process!(reserve_timeout: 10)

Kann jemand Aufschluss geben, wie sollte ich dieses Problem lösen? Das seltsame ist, dass ich diese Begegnung in der Produktion, während andere Informationen zu diesem Thema scheint zu implizieren, es sollte normalerweise nur auftreten, in der Entwicklung.

In der Produktion verwende ich folgende Einstellungen:

config.eager_load = true

config.cache_classes = true.

Autoload-Pfade für alle Umgebungen Rails Standard plus zwei spezielle Ordner („models/Prüfungen“ & „Aufträge/Anliegen“).

eager_load_paths ist nicht modifiziert oder in eine von meinen configs so muss gleich der Rails-Standard.

Ich bin mit Schienen 5 so enable_dependency_loading sollte gleich false in der Produktion.

  • In der Rails-Umgebungen haben Sie versucht, dieses und den Fehler aufgetreten? Was sind die eager_load_paths und autoload_paths für diese Umgebungen? (in der Regel in config/application.rb und config/environments/*.rb)
  • Ah, ich war etwa um die gleichen Fragen wie @anothermh. In Ihrer Anwendung.rb ich vermute, Sie haben eine der beiden gesetzt werden, was nicht der Fall sein sollte in der Produktion. Deaktivieren autoloading mit ` config.enable_dependency_loading = false` sollte helfen.
  • finden Sie modifiziert Antwort. Den Pfad habe ich autoload, sollte ich nicht tun, dass für die Produktion (z.B. setzen Sie diese Einstellung in der Entwicklung.rb und nicht in Anwendung.rb)? Beachten Sie, dass die Konstanten enthalten, die in die zirkuläre Abhängigkeit Fehlermeldung nicht definiert sind, in denen autoload_paths.
  • Sind Sie mit den Frühling? Deaktivieren Sie die Feder mit DISABLE_SPRING=1 in Ihrer Umgebung.
InformationsquelleAutor edwardmp | 2017-07-19

 

3 Replies
  1. 7

    Werden Sie wahrscheinlich brauchen, um Ihre eager_load_paths einschließen, um den Pfad zu den Klassen oder Module, in denen die Fehler. eager_load_paths dokumentiert ist in der Rails-Guides.

    Des Problems, das Sie laufen in ist, dass Schienen ist nicht be-diese Konstanten, wenn die app startet; es lädt automatisch, wenn Sie einige andere Stück code. In einer Multithread-Rails-app, zwei threads haben möglicherweise eine race-Bedingung, wenn Sie versuchen, laden Sie diese Konstanten.

    Erzählen Schienen eifrig laden Sie diese Konstanten, d.h. Sie werden einmal geladen, wenn die Rails-app gestartet wird. Es ist nicht genug zu sagen eager_load = true; Sie geben die Pfade der Klasse oder Modul-Definitionen als auch. In der Rails-Anwendung Konfiguration, dies ist ein Array unter eager_load_paths. Zum Beispiel, zu eifrig laden ActiveJob Klassen:

    config.eager_load_paths += ["#{config.root}/app/jobs"]

    Oder laden Sie eine benutzerdefinierte Modul aus lib/:

    config.eager_load_paths += ["#{config.root}/lib/custom_module"]

    Ändern Sie Ihre eifrig laden Einstellungen beeinflussen das Verhalten der Schienen. Zum Beispiel, in den Schienen development Umgebung, die Sie wahrscheinlich gewöhnt sind, laufen rails server einmal, und jedes mal, wenn Sie und laden Sie in einem der Endpunkte reflektiert alle änderungen an code, den Sie gemacht haben. Das wird nicht funktionieren mit config.eager_load = true, weil die Klassen werden einmal geladen, beim Start. Daher werden Sie in der Regel nur ändern Sie Ihre eager_load Einstellungen für production.

    Update

    Können Sie überprüfen Sie Ihre bestehenden eager_load_paths von der rails console. Zum Beispiel, diese sind die Standard-Werte für neue Schienen 5 app. Wie Sie sehen, kann es nicht geladen app/**/*.rb; es lädt die bestimmte Pfade, die Schienen erwartet zu wissen.

    Rails.application.config.eager_load_paths
    => ["/app/assets",
     "/app/channels",
     "/app/controllers",
     "/app/controllers/concerns",
     "/app/helpers",
     "/app/jobs",
     "/app/mailers",
     "/app/models",
     "/app/models/concerns"]
    • Ich dachte nur, da ich nur load custom Unterverzeichnisse in /app gern laden sogar erforderlich? Ich glaube, ich habe gerade gelesen, Sie sind standardmäßig geladen, als Nachkommen /app
    • Aktualisierte Antwort zu reagieren. Kurze Antwort: Nein, Sie werden standardmäßig nicht geladen.
    • Leider ist das Problem wieder aufgetaucht. Ich glaube nicht, dass dies wirklich die Lösung in diesem Fall.
    • Sie sind herzlich eingeladen, einen link auf das repository, wenn möglich.
    • Vielen Dank für die schnelle Antwort. Leider kann ich nicht an diesem Projekt. Ich denke, ich sollte eine der Methoden bereits in meinem opening post geliefert durch Schienen aber ich weiß nicht, in welcher Eigenschaft. Vielleicht werde ich versuchen, öffnen Sie ein issue auf GitHub für das Rails-Projekt.
    • Können Sie Ihre volle application.rb und die volle production.rb Umfeld-Datei? Sie können schwärzen Sie vertrauliche Informationen.

  2. 4

    In meine Edelsteine (d.h., in plezi und iodine) ich löse diese mit if Aussagen, meistens.

    Finden Sie code wie:

    require 'uri' unless defined?(::URI)

    oder

    begin
      require 'rack/handler' unless defined?(Rack::Handler)
      Rack::Handler::WEBrick = ::Iodine::Rack # Rack::Handler.get(:iodine)
    rescue Exception
    
    end

    Verwendet habe ich diese snippets da Circular dependency detected Warnungen und Fehler.

    Ich weiß nicht, ob das hilft, aber ich dachte, möchten Sie vielleicht, es zu versuchen.

    • Danke. Dies könnte nicht Schienen Kontexten, aber in Rails kann ich nicht wirklich manuell benötigen Sie etwas, aber alle Schienen Klassen sind geladen, statt.
    • Meine Entschuldigung, ich nahm an, Sie waren erfordern Zeug in Ihrer rake Aufgabe, so dass, wenn Sie aufgerufen bundle exec rake es war in Konflikt mit autoloading-Symbole.
    • kein problem, schätzen Sie Ihre Eingabe. Ihre Antwort wäre hilfreich für alle Menschen, die Begegnung mit dem gleichen Problem in nicht-Schienen-Kontexte.
    • Dies funktioniert tatsächlich auf den Kontext beschreiben, in meinem Fall bin ich mit threads, die auf eine verzögerte job rake Arbeiter, und ich war immer die gleiche zirkuläre Abhängigkeiten Fehler zu tun, aber dieser Ansatz war verrückt, da war der code eine Reihe von Abhängigkeiten wie das. Wenn ich einfach die Konstanten-Namen, bevor der thread spawn funktioniert der trick für mich. Diese Antwort regte meine Lösung vielen Dank!!!
    • Gerne 🙂
  3. 4

    Hatte ich dieses Problem beim ausprobieren zwei Edelsteine, die Griffe parallel-Verarbeitung;

    1. pmap gem
    2. parallel gem

    Für pmap ich habe immer ein Fehler mit Bezug auf Zelluloid::TaskTerminated und parallel war ich immer eine zyklische Abhängigkeit erkannt wird, während autoloading-Konstante für bei mir lief es mit mehr als 1 thread. Ich wusste, diese Frage war darauf bezogen, wie meine Klassen und Module wurden eifrig laden und Rennen auf einen thread. Ich versuche die Aktivierung der configs auf true config.cache_classes = true und config.eager_load = true in der Entwicklung env und das Tat den trick für mich.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.