← Alle Beiträge

Lass die Datenbank Nein sagen: Doppelbuchungen verhindern

Zwei Personen, ein Termin, dieselbe Millisekunde. Prüfungen auf Anwendungsebene verlieren dieses Rennen — Postgres kann es gewinnen.

  • PostgreSQL
  • Nebenläufigkeit
  • Backend

Prüfen-dann-Einfügen ist eine Race Condition mit angehängter Kalendereinladung. Unter Last lesen zwei Anfragen beide „der Termin ist frei“ und buchen ihn beide vergnügt. Ich habe gelernt, das nicht mehr im Anwendungscode zu reparieren, sondern die Datenbank ablehnen zu lassen.

Die Falle von Prüfen-dann-Handeln

SELECT ... WHERE Termin frei und dann INSERT hat eine Lücke zwischen Lesen und Schreiben. Zwei gleichzeitige Anfragen können beide die Prüfung bestehen, bevor eine von ihnen einfügt. Keine noch so sorgfältige Anwendungslogik schließt dieses Fenster zuverlässig — man macht das Rennen nur enger, beseitigt es aber nicht.

Mach die Bedingung physisch

Postgres-EXCLUDE-Bedingungen mit einem Range-Typ weisen jede Zeile ab, die sich mit einer bestehenden überschneidet — beim Commit, innerhalb der Engine. Die zweite Buchung bekommt kein höfliches „Entschuldigung“ von deinem Code; sie ist physisch unmöglich zu speichern. Das ist Korrektheit, die man nicht zu schreiben vergessen, nicht versehentlich umgehen und nicht in einem Refactoring verlieren kann.

Zeitzonen sind das andere Monster

„9:00“ ist ohne Zone bedeutungslos, und die Sommerzeit sorgt dafür, dass manche Ortszeiten nicht existieren, während andere zweimal vorkommen. Berechne die Verfügbarkeit mit der Temporal API gegen echte Zeitzonen, speichere die Zeitpunkte in UTC und stelle sie in der Zone des Betrachters dar. Selbstgestrickte Datumsrechnung ist der Ort, an dem Buchungs-Apps sterben.

Seiteneffekte brauchen eine Outbox

Die Bestätigungs-E-Mail darf nicht verschwinden, wenn die Anfrage direkt nach dem Commit abstürzt. Schreibe die Absicht innerhalb derselben Transaktion in eine Outbox-Tabelle und stelle sie asynchron zu. „Committet, wird gesendet“ schlägt „gesendet, vielleicht committet“.

Das durchgängige Motiv: Schiebe die Korrektheit auf die Ebene, auf der sie erzwungen werden kann — nicht bloß erhofft.