Worum es geht
Zwei Personen öffnen dasselbe Objekt, beide ändern etwas, beide speichern. Was passiert?
Last write wins
sequenceDiagram
participant A as Anna (Client)
participant C as CDMS
participant B as Ben (Client)
A->>C: liest Kunde (email = alt@…, phone = 111)
B->>C: liest Kunde (email = alt@…, phone = 111)
A->>C: PUT { email: anna@…, phone: 111 }
C-->>A: 200
B->>C: PUT { email: alt@…, phone: 222 }
C-->>B: 200
Note over C: email = alt@… (Annas Änderung ist weg)<br/>phone = 222
Ben hat Annas neue E-Mail nie gesehen. Sein PUT beschreibt den ganzen Zielzustand, also auch die alte E-Mail. CDMS prüft nicht, ob sich das Objekt seit Bens Lesen geändert hat, und speichert Bens Stand.
PATCH verkleinert den Konflikt
Mit PATCH schickt jeder nur, was er geändert hat. Dann überschreiben sich zwei Personen nur, wenn sie dasselbe Feld ändern.
| beide mit PUT | beide mit PATCH | |
|---|---|---|
| Anna schickt | email und phone | nur email |
| Ben schickt | email und phone | nur phone |
| Ergebnis | Annas E-Mail ist verloren | beide Änderungen bleiben |
Ändern beide dasselbe Feld, gewinnt auch bei PATCH die letzte Anfrage. Siehe PUT oder PATCH?
Datei-Modelle: 409 bei überlappenden Anfragen
Ein Datei-Modell hat ein internes Systemfeld _version, einen Zähler. Der Client sieht es nicht und schickt es nicht mit. CDMS nutzt es, um zwei Anfragen zu erkennen, die zur selben Zeit dasselbe Objekt schreiben:
-
1Client→CDMSAnfrage 1:
PUT /update/{id}/uploadmit einer neuen Datei -
2Client→CDMSAnfrage 2, kurz danach: ebenfalls ein Upload in dasselbe Objekt
-
3CDMS→DatabaseAnfrage 1 beansprucht das Objekt und erhöht
_version, bevor sie die Datei schreibt -
4CDMS→DatabaseAnfrage 2 will dasselbe, findet aber schon eine höhere
_versionvor -
5CDMS→ClientAnfrage 2 → 409
CDMS_OPTIMISTIC_LOCK_CONFLICT, ihre Datei wird nicht übernommen -
6CDMS→ClientAnfrage 1 → 200
{
"error": "CodamaiPersistenceException",
"messageKey": "CDMS_OPTIMISTIC_LOCK_CONFLICT",
"code": "409",
"layer": "database"
}Objekt neu lesen,
prüfen, ob der Upload noch nötig ist,
dann erneut schicken.Das gilt auch für überlappende Änderungen der übrigen Felder eines Datei-Objekts. Zwei Anfragen nacheinander erkennt es nicht: Liegt zwischen Lesen und Speichern eine Pause, gewinnt auch hier die letzte.
Normales Modell und Datei-Modell im Vergleich
| Normales Modell | Datei-Modell | |
|---|---|---|
| Versionsfeld | keins | _version, intern |
| Client schickt etwas mit | nein | nein |
| zwei überlappende Anfragen | die spätere gewinnt | die zweite bekommt 409 |
| gelesen vor 10 Minuten, jetzt gespeichert | die spätere gewinnt | die spätere gewinnt |
Anlegen oder ändern entscheidet der Client
Einen Endpunkt, der selbst entscheidet, ob er anlegt oder ändert (save, „upsert“), gibt es nicht. Der Client entscheidet anhand der id:
| Objekt hat eine id | Anfrage |
|---|---|
| nein | POST /create, danach die id aus der Antwort merken |
| ja | PUT oder PATCH /update/{id} |
Klickt jemand zweimal auf „Speichern“, bevor die erste Antwort da ist, entstehen zwei Objekte. Sperre den Knopf, bis die Antwort da ist. Bei Singletons verhindert CDMS ein zweites Objekt selbst: Das zweite create liefert 400 object-already-exists|use-update.
Fallen
Wie es weitergeht
- Welches Verb wofür: PUT oder PATCH? Die null-Falle
- Dateien hochladen: Hochladen
- Was in einer Transaktion zusammengehört: Ein Request, eine Transaktion