Wir haben ein Szenario, in dem wir mehrere Feeds unter einem Website-Modell speichern müssen, wie folgt:
{
id: site_id
name: site_name
feeds: [
{
url: feed_url_1
date: feed_update_date_1
},
{
url: feed_url_2
date: feed_update_date_2
},
...
]
}
Da feeds
ein Array ist, können wir es mit $set
, $push
oder $addToSet
aktualisieren.
Es können 2 verschiedene Race Conditions (Schreibverzug) auftreten, wenn unsere gleichzeitige Anwendung (Warteschlange) versucht, dasselbe Website-Modell zu aktualisieren.
Wenn wir $set
wählen und Duplikate auf der Clientseite verhindern, kann es vorkommen, dass bei einem Schreibvorgang an dasselbe Website zwei Feeds verloren gehen können, wie in folgender Sequenz:
Gehen Sie davon aus, dass eine Wordpress-Seite 2 Feeds (RSS und ATOM) extrahiert und an Q1 und Q2 sendet.
Q1: vorhandenen Feed laden, überprüfen, ob RSS-Feed neu ist
Q2: vorhandenen Feed laden, überprüfen, ob ATOM-Feed neu ist
Q1: $set feeds => [RSS]
Q2: $set feeds => [ATOM]
Jetzt geht der RSS-Feed verloren.
Wenn wir $push
oder $addToSet
wählen, kann Folgendes passieren:
Benutzer A fügt eine Website hinzu und fügt den RSS-Feed Q1 hinzu
Benutzer B fügt dieselbe Website hinzu und fügt denselben RSS-Feed Q2 hinzu
Q1: vorhandenen Feed laden, überprüfen, ob RSS-Feed neu ist
Q2: vorhandenen Feed laden, überprüfen, ob RSS-Feed neu ist
Q1: $push RSS
Q2: $push RSS
Jetzt wurde der RSS-Feed dupliziert
Wenn unser Datenmodell einfach { url }
wäre, würde $addToSet
gegen doppelte Feeds schützen. Leider ist dies jedoch nicht der Fall, da sich das date
-Attribut unterscheiden kann. Daher ist $addToSet
nicht viel sicherer als $push
.
Wir haben einige mögliche Lösungsansätze für dieses Problem durchdacht, aber keiner davon ist ideal angesichts unseres straffen Zeitplans.
-
Entkoppeln Sie Feeds von der Website in eine eigene Sammlung, schützen Sie sie nur mit
url
und passen Sie unser Modell und Repository entsprechend an. -
Fügen Sie zuerst ein teilweises
{ url }
in das Website-Modell ein und aktualisieren Sie sie dann mit zusätzlichen Informationen. Dadurch sollte$addToSet
verwendbar werden, aber es könnte andere Warteschlangen brechen, die erfordern, dass dasdate
immer vorhanden ist (Test erforderlich). -
Lassen Sie die Race Condition wie sie ist, fügen Sie zuerst den Feed mit
$push
hinzu und verwenden Sie eine Hintergrundwarteschlange, um Duplikate später zu erkennen und zu entfernen.
(Es könnte eine 4. Lösung geben, falls Upsert mit Positionsabfrage funktioniert, aber soweit ich weiß, hat MongoDB v2.4 dies noch nicht)
Ich frage mich, ob es bessere Alternativen zur Lösung dieser Art von Race Condition gibt. Oder ob es bewährte Verfahren dafür gibt.