2010-10-20 11 views
5

Ich habe, was ich denke, muss ein Nebenläufigkeitsproblem sein. Ich benutze Passagier, Schienen 2.3.5, Mongoid 1.9.2 und Mongo Ruby-Treiber 1.0.9. Ich verwende jQuery, um Daten anzufordern, die aus MongoDB abgerufen und dann im Browser gerendert werden. Alles funktioniert gut, bis ich anfing, zwei solche Anfragen gleichzeitig zu machen. In dem Modell, das sind die Methoden, die von den Anfragen ausgeführt werden soll:Ruby Mongo oder Mongoid Concurrency Problem

Class Visit 
    include Mongoid::Document 
    ... 
    def self.cancellations_and_visits_by_therapist_graph(clinic_id) 
    visits = collection.group("function(x){ return { resource_id : x.resource_id } }", 
      {:clinic_id => clinic_id, :visit_date => { "$gte" => Time.now - 6.months, "$lte" => Time.now}}, 
      {:visits => 0, :cancel_no_shows => 0}, 
      'function(obj, count) { 
       if (obj.visit_status == "NO SHOW" || obj.visits_status == "CANCELLED") { 
       count.cancel_no_shows += 1; 
       } else { 
       count.visits += 1; 
       } 

      }') 

    visits = visits.group_by {|g| g['resource_id']} 

    Resource.any_in(:mysql_id => visits.keys).order_by([:last_name, :asc]).order_by([:first_name, :asc]).inject({ 'visits' => [], 'cancel_no_shows' => [], 'xlabels' => []}) do |formatted_visits, resource| 
     formatted_visits['visits'] << visits[resource.mysql_id.to_f].first['visits'] 
     formatted_visits['cancel_no_shows'] << visits[resource.mysql_id.to_f].first['cancel_no_shows'] 
     formatted_visits['xlabels'] << resource.last_name + ", " + resource.first_name 
     formatted_visits 
    end 
    end 



    def self.total_visits_for_graph(practice_id) 
    visits = collection.group("function(x) { return { clinic_id : x.clinic_id } }", 
          {:practice_id => practice_id, :visit_status => 'COMPLETE', :visit_date => { "$gte" => Time.now - 6.months, "$lte" => Time.now}}, 
          {:visits => 0}, "function(obj, count) { count.visits += 1; }") 

    visits = visits.group_by {|g| g['clinic_id']} 
    Clinic.any_in(:mysql_id => visits.keys).order_by([:name, :asc]).inject({ 'data' => [], 'xlabels' => []}) do |formatted_visits, clinic| 
     formatted_visits['data'] << visits[clinic.mysql_id.to_f].first['visits'] 
     formatted_visits['xlabels'] << clinic.name 
     formatted_visits 
    end 
    end 
end 

Der beste Weg, um das Problem zu beschreiben, ist, dass die Ergebnisse von Mongo sind mit dem falschen Objekt übergeben zu werden. Ich lookated ein Beispiel dafür:

Dies wurde zurückgegeben, als ich CLinic.any_in genannt (es ist ein Ergebnis aus einer der Gruppen):

{"group"=>{"$keyf"=>"function(x){ return { resource_id : x.resource_id } }", "cond"=>{:clinic_id=>101, :visit_date=>{"$gte"=>Tue Apr 20 15:34:37 +0800 2010, "$lte"=>Wed Oct 20 15:34:37 +0800 2010}}, "ns"=>"visits", "initial"=>{:visits=>0, :cancel_no_shows=>0}, "$reduce"=>"function(obj, count) {\n    if (obj.visit_status == \"NO SHOW\" || obj.visits_status == \"CANCELLED\") {\n    count.cancel_no_shows += 1;\n    } else {\n    count.visits += 1;\n    }\n\n   }"}} 

Das (eine Klinik Objekt) wurde durch die Sammlung zurückgegeben .group nennen:

{"_id"=>BSON::ObjectId('4cb7d72b3bc5457800ce2e6f'), "name"=>"Corona", "practice_id"=>39, "mysql_id"=>101} 

Wie bei allen guten concurancy Probleme die Ergebnisse sind randome, manchmal funktioniert es gut und manchmal bläst sie nach oben. Ich bin neu bei Mongo und Mongoid, also bin ich mir eigentlich nicht sicher, ob das ein Problem mit Mongoid oder dem Mongo Driver ist, aber ich denke es ist mit Mongoid verwandt. Ich nehme meinen Initialisierer mit, den ich verwende, um Mongoid in Schienen zu laden. Irgendwelche Ideen oder sogar nur zusätzliche Debugging-Ideen sind sehr zu schätzen.

Anschluss

mongoid_conf = YAML::load_file(Rails.root.join('config/mongoid.yml'))[Rails.env] 

Mongoid.configure do |config| 
    config.master = Mongo::Connection.new(mongoid_conf['host'], 27017, :pool_size => 5, :timeout => 5).db(mongoid_conf['database']) 
end 

Antwort

5

fand ich die Lösung für dieses Problem. Es war weder der Mongo-Fahrer noch der Mongoid, es war Passagier. Wenn Passenger den Rails-Prozess überspannt, verzweigt er die aktuelle Instanz, sodass die Dateideskriptoren (einschließlich der TCP-Deskriptoren über App-Instanzen hinweg freigegeben werden). Dies bedeutet, dass dieser Mongo von demselben Socket geschrieben und gelesen wird, was zu dem Concurrency-Problem führt. Die Lösung ist, Mongo wieder zu verbinden, wenn es Gabeln gibt. Das ist die Lösung, die ich gefunden:

# Handle the creation of new processes by Phusion Passenger 
if defined?(PhusionPassenger) 
    PhusionPassenger.on_event(:starting_worker_process) do |forked| 
    if forked 
     # We're in smart spawning mode. 

     # Reset the connection to MongoDB 
     Mongoid.config.master.connection.close 
     load File.join(RAILS_ROOT, 'config/initializers/mongoid_init.rb') 
    else 
     # We're in conservative spawning mode. We don't need to do anything.  
    end 
    end 
end 

Referenz http://groups.google.com/group/mongodb-user/browse_thread/thread/f31e2d23de38136a für die ursprüngliche Antwort Posting und Diskussion.