TATECHATLAS
◎ Deutsch
Web und APIs

Doppelte API-Übermittlungen: Idempotenzvertrag entwerfen, bevor ein Schlüssel hinzugefügt wird

Rufen Sie, Nutzlast, atomaren Anspruch und Wiedergabepolicy so fest, dass eine Wiederholung ein vorhersehbares Anwendungsergebnis hat.

Auf dieser Seite

Bei einer wiederholten Auftragsübermittlung soll für denselben authentifizierten Aufrufer und dieselbe logische Nutzlast ein Schlüssel wiederverwendet werden. Die Anwendung kann diese Kombination atomar beanspruchen und das abgeschlossene Ergebnis zur Wiedergabe vorhalten. Eine geänderte Nutzlast mit demselben Schlüssel sollte einen dokumentierten Anwendungskonflikt erhalten. Eine eindeutige Datenbankzeile koordiniert die Ansprüche, garantiert aber allein nicht, dass eine Zahlung, E-Mail oder andere externe Wirkung genau einmal eintritt.

HTTP-Semantik von dem Anwendungsvertrag trennen

Eine idempotente Operation hat dieselbe beabsichtigte Serverwirkung, wenn sie wiederholt wird, wie bei einmaliger Ausführung. Damit diese Definition gilt, müssen die Antworten nicht identisch sein. Ein POST-Endpunkt erwirbt nicht einfach durch einen zusätzlichen Client-Header einen sicheren Wiederholungsvertrag. Der Server muss implementieren und dokumentieren, wie er diesen Schlüssel auslegt, welche Operationen er abdeckt und wie Wiederholungen mit Authentifizierung und gespeichertem Zustand interagieren.

Schlüssel auf einen vertrauenswürdigen Aufrufer eingrenzen

Im hypothetischen Beispiel gehört der Schlüssel k1 zu einem authentifizierten Aufrufer und einer Auftragserstellungs-Operation. Ein anderer Aufrufer, der k1 verwendet, darf nicht das Ergebnis des ersten Aufrufers erhalten. Die Aufruferidentität aus der vertrauenswürdigen Authentifizierung beziehen, nicht aus einem frei übergebenen Nutzlastfeld. Festlegen, ob Schlüssel einen Namespace über Operationen teilen oder auf einen bestimmten Endpunkt eingegrenzt sind, und diese Eingrenzung in der Datenbank-Eindeutigkeitsregel bewahren.

Nutzlastäquivalenz festlegen

Derselbe Schlüssel sollte dieselbe logische Übermittlung repräsentieren. Definieren, welche Felder Teil der Operation sind und wie die Anwendung sie vergleicht, zum Beispiel über eine kanonische Darstellung oder einen Digest nach einer dokumentierten Regel. Roh-JSON-Bytes können sich unterscheiden, aber dieselben Daten darstellen, daher ist Byte-Gleichheit eine Policy-Entscheidung. Umgekehrt kann das Ausschließen eines wichtigen Felds wie des Betrags unterschiedliche Aufträge fälschlich als äquivalent identifizieren.

Die konstruierte Wiederholung durchgehen

Angenommen, Aufrufer A übermittelt Schlüssel k1 mit einer Nutzlast, die zwei Einheiten des Artikels X anfordert. Die erste erfolgreiche Anfrage speichert ein Auftragsergebnis. Eine Wiederholung durch A mit k1 und der äquivalenten Nutzlast gibt dieses vorhaltene Ergebnis unter diesem vorgeschlagenen Vertrag zurück. Eine Anfrage mit k1, die drei Einheiten anfordert, wird als Nutzlastabweichung abgelehnt. Dies ist eine Designillustration, keine Behauptung, dass jede bestehende API denselben Statuscode oder dasselbe Wiedergabeverhalten nutzt.

Schlüssel atomar beanspruchen

Eine Check-then-Insert-Folge kann ins Wettrennen geraten: Zwei Anfragen können beide keinen vorhandenen Schlüssel sehen. Eine Datenbank-Eindeutigkeitsbedingung über die gewählte Kombination aus Aufrufer, Operation und Schlüsselumfang kann einen einzelnen gespeicherten Anspruch erzwingen. PostgreSQL INSERT ON CONFLICT kann bei der Koordinierung der Einfügung helfen. Die Anwendung muss weiterhin auslegen, ob sie einen neuen Anspruch besitzt oder einen vorhandenen gefunden hat, und darf nicht jede verlierende Anfrage trotzdem die geschützte Operation ausführen lassen.

Verarbeitungs- und abgeschlossene Zustände darstellen

Genügend Zustand speichern, um eine noch verarbeitete Anfrage von einer mit wiedergabefähigem Ergebnis zu unterscheiden. Definieren, wie eine gleichzeitige Wiederholung reagiert, während der erste Versuch läuft: Warten, eine dokumentierte temporäre Antwort oder eine Wiederholungsanweisung sind mögliche Policies. Abgeschlossenen Zustand und sein Ergebnis konsistent mit Datenbankänderungen speichern, wo möglich. Das Vorhandensein einer beliebigen Schlüsselzeile nicht als Beweis dafür behandeln, dass der Auftrag erfolgreich abgeschlossen wurde.

Externe Wirkungen und Crash-Fenster behandeln

Ein Zahlungsanbieter oder E-Mail-Dienst nimmt nicht automatisch an der Datenbanktransaktion teil. Ein Absturz nach einer externen Wirkung, aber vor dem Speichern des abgeschlossenen Ergebnisses, erzeugt ein Wiederherstellungsproblem. Ein persistenter Outbox, anbieterunterstützte Deduplizierung oder eine explizite Abstimmung können je nach Wirkung Teil einer Lösung sein. Jede hat ihren eigenen Vertrag. Das bloße Einwickeln der lokalen Schlüssel-Einfügung in eine Transaktion begründet kein genau-einmaliges Verhalten über Systeme hinweg.

Aufbewahrung und Wiederherstellungsgrenzen dokumentieren

Dokumentieren, wie lange Schlüssel und Ergebnisse aufbewahrt werden, was eine Wiedergabe zurückgibt und was nach Ablauf geschieht. Das Entfernen eines Datensatzes kann ermöglichen, dass eine spätere Anfrage mit demselben Schlüssel zu einer neuen Übermittlung wird. Auch die Wiederherstellung für verlassene Verarbeitungszustände und ob fehlgeschlagene Versuche wiederverwendbar sind, definieren. Diese Entscheidungen beeinflussen sowohl Korrektheit als auch Speicher. Ein Client muss eine sichere Wiederholung von der Erstellung einer neuen logischen Operation unterscheiden können.

Was Sie prüfen sollten

  • Schlüssel nur für dieselbe logische Operation wiederverwenden.
  • Nachschau auf den authentifizierten Aufrufer eingrenzen.
  • Nutzlastäquivalenz und Fehlverhalten bei Abweichung definieren.
  • Anspruch atomar und eindeutig machen.
  • Wiederherstellung für externe Wirkungen und abgelaufene Schlüssel planen.

Dieser Leitfaden beschreibt einen hypothetischen Anwendungsvertrag, keine vollständige Serverimplementierung und keinen universellen Idempotency-Key-Standard. Datenbankeindeutigkeit und HTTP-Idempotenz stellen allein keine genau-einmaligen externen Nebenwirkungen her.

Quellen

  1. MDN: HTTP idempotency ↗
  2. PostgreSQL: unique constraints ↗
  3. PostgreSQL: atomic INSERT ON CONFLICT ↗
Nach oben ↑