2016-04-03 16 views
2

Hier sind fünf Dateien hinzugefügt my app (keine Datenbank, kein Setup als solche erforderlich) mit:Handhabung zirkuläre Abhängigkeit in Schienen während Fäden

lib/Aufgaben/precomputation.rake

namespace :precomputation do 
    desc "This fetches data for precomputation" 
    task fetch_all: :environment do 
     Precomputation.precompute_all_data 
    # end 
    end 
end 

app/models /precomputation.rb

class Precomputation 
    def self.precompute_all_data 
    ad_accounts = [1,2,3] 
    bgthread = BackgroundThread::BGThreadPool.new(1) 
    tasks = [] 
    ad_accounts.each do |ad_account_id| 
     p = Proc.new do 
     begin 
      MongoPipeline::FbAdCampaignMongoPipeline.new(ad_account_id).fetch_all 
      false 
     ensure 
      GC.start 
     end 
     end 
     tasks << [p, "test #{ad_account_id}"] 
    end 
    bgthread.add_randomized_tasks(tasks) 
    bgthread.do_work 
    end 
end 

app/Modelle/mongo_pipeline.rb

module MongoPipeline 
    class Base 
    def initialize(ad_account_id) 
    end 

    def insert_data 
     puts 'inserting data' 
    end 

    def fetch_all 
     extract_data # Child Class defines this method 
     insert_data # Base class defines this method 
    end 
    end 
end 

app/models/mongo_pipeline/fb_ad_campaign_mongo_pipeline.rb

module MongoPipeline 
    class FbAdCampaignMongoPipeline < MongoPipeline::Base 
    def extract_data 
     puts 'here is campaign data' 
    end 
    end 
end 

und app/models/background_thread.rb

(HINWEIS: Alternative Implementierung parallel gem und keine Hintergrundthread mit kollabiert auch mit ähnlichen Fehler - : https://github.com/pratik60/circular_dependency_havoc/tree/parallel)

Fehlerprotokoll

rake aborted! 
Circular dependency detected while autoloading constant MongoPipeline 
/Users/pratikbothra/.rvm/gems/ruby-2.2.2/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:492:in `load_missing_constant' 
/Users/pratikbothra/.rvm/gems/ruby-2.2.2/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:184:in `const_missing' 
/Users/pratikbothra/.rvm/gems/ruby-2.2.2/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:526:in `load_missing_constant' 
/Users/pratikbothra/.rvm/gems/ruby-2.2.2/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:184:in `const_missing' 
/webapps/circular_dependency_havoc/app/models/precomputation.rb:9:in `block (2 levels) in precompute_all_data' 
/webapps/circular_dependency_havoc/app/models/background_thread.rb:91:in `call' 
/webapps/circular_dependency_havoc/app/models/background_thread.rb:91:in `block in background' 
Tasks: TOP => precomputation:fetch_all 
(See full trace by running task with --trace) 

Irgendwelche Ideen, was ich falsch mache? Die Hintergrund-Thread-Bibliothek wurde geklont und einfach modifiziert. Fühlen Sie sich frei, es zu ersetzen, wenn Sie denken, dass das das Problem ist. Irgendwelche Vorschläge, irgendwelche Ideen sind mehr als willkommen.

+0

Themen und automatisches Laden nicht tun gut zusammenarbeiten. Können Sie dies in der Produktionsumgebung statt in der Entwicklungsumgebung ausführen? –

+0

@SteveJorgensen Nein, kein Glück. Gibt es noch andere Bibliotheken, die ich benutzen möchte? –

Antwort

1

Ich änderte zunächst diese Einstellung

config/environments/development.rb 

config.eager_load = true 

Dies obwohl nicht helfen!

Und ich brauchte

config/initializers/eager_load.rb: 

Rails.application.eager_load! unless Rails.env.test? 

Sie auch eifrig Last die gesamte lib Ordner hinzufügen müssen, wenn Sie eine verwenden (automatisches Laden nicht genug ist).

config/application.rb 

config.eager_load_paths += Dir["#{Rails.root}/lib/**/"] 

Stellen Sie außerdem sicher, dass, wenn devise in Initialisierer verwendet wird, um es zu 01_devise.rb oder etwas umbenannt wird, wie initializers alphabetisch geladen sind, und Ihre Benutzer oder Admin, wird es verweisen.

Wahrscheinlich schlagen Sie vor, dass in den Tests eager_load übersprungen wird, da es suboptimal ist, und wenn Sie Threads intern nicht verwenden, überspringen Sie es ganz!

+0

Sie können Ihre eigenen Antworten akzeptieren, wenn Sie möchten ... –

2

Ich stieß auf dieses Problem beim Erstellen eines Thread-Loops in einem Rake-Task, um externe Server abzufragen, und kam zu der gleichen Schlussfolgerung, dass es Autoload & unvorhersehbare Race-Condition-Related war. Ich wollte aber nicht einfach nur eifrig weitermachen, also gab es zwei Möglichkeiten, wie ich das angehen konnte. Einer war, um herauszufinden, welche Klassen wurden in meiner Aufgabe immer geladen und sich in der Mutter laden, vor alle Fäden des Laich:

# preload classes that showed circular dependencies just in this task 
MediaFile 
VideoPlatformIntegration 
Tag 

10.times.map{Thread.new{...}} 

Dieser arbeitete wie ein Charme, aber es war etwas seltsam Produktion Code zu setzen in und nicht robust gegenüber irgendwelchen Änderungen in der Aufgabe oder irgendwelchen von ihr aufgerufenen Methoden.

Die andere ist unvollkommener, ändert aber nur das Verhalten in der Entwicklungsumgebung und ist nicht darauf angewiesen, alles zu wissen, was zu dieser Bedingung führen könnte.Da es nur in der Entwicklung ist, hielt ich dies akzeptabel: Schlaf für eine zufällige Menge an Zeit (zwischen 0 und 1 Sekunde) zu Beginn eines jeden Anfang thread:

sleep(Random.rand) if Rails.env == "development"

Dieser Schlaf verhindert, dass die Fäden aus ab Gleichzeitig verringert sich die Wahrscheinlichkeit von Wettkämpfen in Beladungsklassen drastisch. I Proof-of-concept hier diese eine einfache Charge von 10 Threads, ohne Schlaf das Skript 4-mal mit und 4-mal ausgeführt wird, eine zuverlässige zirkulären Abhängigkeit Fehler ohne Schlaf zeigt:

[video_platform_integration] [email protected]~/3p/app3$ rails runner '10.times.map{Thread.new{MediaFile.last rescue puts($!)}}' 
Circular dependency detected while autoloading constant MediaFile 
Circular dependency detected while autoloading constant MediaFile 
[video_platform_integration] [email protected]~/3p/app3$ rails runner '10.times.map{Thread.new{MediaFile.last rescue puts($!)}}' 
Circular dependency detected while autoloading constant MediaFile 
[video_platform_integration] [email protected]~/3p/app3$ rails runner '10.times.map{Thread.new{MediaFile.last rescue puts($!)}}' 
[video_platform_integration] [email protected]~/3p/app3$ rails runner '10.times.map{Thread.new{MediaFile.last rescue puts($!)}}' 
Circular dependency detected while autoloading constant MediaFile 
Circular dependency detected while autoloading constant MediaFile 
[video_platform_integration] [email protected]~/3p/app3$ rails runner '10.times.map{Thread.new{sleep(Random.rand); MediaFile.last rescue puts($!)}}' 
[video_platform_integration] [email protected]~/3p/app3$ rails runner '10.times.map{Thread.new{sleep(Random.rand); MediaFile.last rescue puts($!)}}' 
[video_platform_integration] [email protected]~/3p/app3$ rails runner '10.times.map{Thread.new{sleep(Random.rand); MediaFile.last rescue puts($!)}}' 
[video_platform_integration] [email protected]~/3p/app3$ rails runner '10.times.map{Thread.new{sleep(Random.rand); MediaFile.last rescue puts($!)}}' 
Verwandte Themen