2013-08-02 2 views
7

in meinem Server/server.jsMeteor: Könnte eine Race Condition mit Meteor.collections auf der Serverseite passieren?

Meteor.methods({ 
    saveOnServer: function() { 
     var totalCount = Collections.find({ 
      "some": "condition" 
     }).count(); 
     if (totalCount) { 
      var customerId = Collections.update('someId', { 
       "$addToSet": { 
        objects: object 
       } 
      }, function(err) { 
       if (err) { 
        throw err; 
       } else { 
        return true; 
       } 
      }); 
     } else {} 
    } 
}); 

Ich habe Angst, dass, wenn saveOnServer() von 2-Clients zur gleichen Zeit aufgerufen wird, wird es die gleiche totalcount für jeden Client zurück und grundsätzlich gleiches Einfügen am Ende Ganzzahl in Objekt-ID. Das Endziel besteht darin, eine Zeile auf der Serverseite mit einer atomaren Operation einzufügen, die erst abgeschlossen wird, wenn die totalCount erfolgreich zurückgegeben wird und das Dokument eingefügt wird, um sicherzustellen, dass keine doppelte ID existiert? Ich versuche, die mongodb _id nicht zu benutzen, aber habe meine eigene ganzzahlige ID-Spalte.

Ich frage mich, wie ich sicherstellen kann, dass ein Feld für jeden Einfügevorgang automatisch inkrementiert wird? Ich verlasse mich derzeit auf die Gesamtzahl der Dokumente. Ist hier eine Race Condition möglich? Wenn ja, was ist der Meteor-Weg, damit umzugehen?

+0

im Prinzip ist der Meteorcode zu weit von den Daten entfernt, um dies zu gewährleisten. Es ist eine bessere Idee, dbms-Tools für eine solche Validierung zu verwenden. – dandavis

+1

auf der Serverseite ist alles synchron, um Callback-Hölle mit Knoten-Fasern zu vermeiden? Aber meteor.collection verwaltet mongodb, gibt es eine Möglichkeit, einen Meteor zu garantieren. Das Sammelobjekt wird atomar oder race condition free sein? – KJW

+1

Gleiche Frage ist hier und beantwortet http://stackoverflow.com/questions/15886833/how-can-i-create-an-auto-increment-field-on-meteor. Ihr Code ist kein Problem, es sei denn, Sie arbeiten auf mehreren Servern. – user728291

Antwort

9

Im Gleichzeitigkeitsmodell von Meteor können Sie sich eine ganze Methode als einen unterbrechungsfreien Block von Dingen vorstellen, die passiert. Damit Meteor von einer Methode auf die andere umschalten kann, um eine andere Methode zu starten, müssen Sie "nachgeben" - die Methode muss signalisieren: "Ich kann unterbrochen werden."

Methoden liefern, wenn sie etwas asynchrones tun, was in der Praxis jedes Mal bedeutet, wenn Sie eine Datenbankaktualisierung durchführen oder eine Methode mit einem Callback in Meteor 0.6.5 und höher aufrufen. Da Sie Ihren update Anruf einen Rückruf geben, wird Meteor immer versuchen, etwas zwischen dem Anruf update und dem Rückruf update zu tun. In Meteor 0.6.4.2 und früheren Versionen waren Datenbankupdates jedoch unabhängig von der Verwendung von Callbacks unterbrechungsfrei.

Es treten jedoch mehrere Aufrufe an saveOnServer in der angegebenen Reihenfolge auf und verursachen keine Racebedingung. Sie können this.unblock() anrufen, damit mehrere Anrufe an saveOnServer "gleichzeitig" stattfinden -i.e., Nicht die gleiche Warteschlange, unter der Bezeichnung saveOnServer queue, von unterbrechungsfreien Blöcken von Sachen.

Gegeben der Code, den Sie haben, kann eine andere Methode, die Collections ändert, den Wert count() zwischen dem Anruf und dem Update ändern.

Sie können macht die andere ungültige Mitte ein Verfahren verhindern, indem die folgenden Datenmodell Umsetzung:

saveOnServer : function() { 
// ... 
    Collections.update({_id:someId, initialized:true, collectionCount: {$gt: 0}}, 
    {$addToSet: {objects: object}}); 
///... 
} 

Wenn Objekte zu Collections Zugabe:

insertObject: function() { 
//... 
    var count = Collections.find({some: condition}).count(); 
    Collections.insert({_id:someId, initialized:false, collectionCount: count}); 
    Collections.update({initialized:false}, 
    {$set:{initialized:true}, $inc: {collectionCount: 1}}); 
} 

Hinweis, während dies ineffizient zu sein scheint, Es spiegelt die genauen Kosten wider, die beim Durchführen eines Updates und beim Einfügen in andere Methoden erforderlich sind. In saveOnServer können Sie nicht einfügen.

Umgekehrt, wenn Sie den Rückruf von Collections.update entfernt, wird es synchron auftreten, und es wird keine Rennen Anlage Meteor 0.6.5 und später sein.

+3

Es wird nur in der Reihenfolge geschehen, wenn Sie nur 1 Server verwenden. Wenn du 2+ Server hast, denke ich, dass du Race Conditions auf mongodb schreiben wirst. – gabrielhpugliese

+0

Überprüfen Sie meine Notiz, um zu klären, wie ich den Meteor-Code besser verstehe. – DoctorPangloss

+0

Neue Notiz hinzugefügt. Meine Kommentare darüber, Callbacks zu 'update' zu ​​geben, waren bis 0.6.5 – DoctorPangloss

1

Sie können diese Kollektion machen haben einen eindeutigen Schlüssel auf einem Indexfeld und dann den neusten Stand bringen, wie folgt:

1) Jedes Mal, wenn Sie in die Sammlung einzufügen, gehen Sie zunächst eine Abfrage, um den maximalen Index und Einsatz zu bekommen das Dokument mit dem Index + 1.

2) Um die Anzahl der Dokumente zu ermitteln, führen Sie einfach die Abfrage aus, um das Maximum des Indexes zu erhalten.

Einfügen ist jetzt ein Paar Abfragen, ein Lese- und ein Schreibvorgang, so dass es fehlschlagen kann. (DB-Ops können jedoch immer scheitern.) Es kann jedoch nie verlassen die Datenbank in einem inkonsistenten Zustand - der Mongo-Index wird dies garantieren.

Die Syntax für einen Index in Meteor Aufbau dieser ist:

MyCollection._ensureIndex('index', {unique: 1}); 
1

andere Möglichkeit, dies zu tun, ist von einem Mechanismus Hibernate/JPA folgt - und das ist ein Kollisionsfeld einzurichten. In den meisten Fällen kann dies ein Aktualisierungszeitstempel sein, der bei jedem Update festgelegt wird. Überprüfen Sie kurz vor dem Aktualisieren den Aktualisierungszeitstempel. Dann können Sie das Update angeben, bei dem der Aktualisierungszeitstempel das ist, was Sie gerade abgerufen haben. Wenn es sich in der Zwischenzeit geändert hat, wird das Update nicht passieren - und Sie überprüfen den Rückgabecode/Anzahl, dass die Zeile aktualisiert wurde oder nicht. JPA macht dies automatisch für Sie, wenn Sie eine Annotation für dieses Kollisionsfeld hinzufügen - aber das ist im Wesentlichen, was es im Hintergrund tut

Verwandte Themen