Software

Was ist Idempotenz? Doppelte API Anfragen sicher verhindern

Talha Aslan 19 Minuten Lesezeit 2 Aufrufe

Was ist Idempotenz?

Idempotenz ist die Eigenschaft einer Operation, nach einmaliger oder mehrfacher Ausführung denselben Endzustand zu hinterlassen. Bei einer API heißt das: Eine Anfrage, die Sie nach einem Netzwerkfehler erneut senden, erzeugt keine zweite Bestellung, keine zweite Abbuchung und keinen zweiten Datensatz.

Kurz gesagt macht Idempotenz die Wiederholung ungefährlich. Verbindungen brechen ab, Antworten gehen verloren, und Clients versuchen es erneut, weil sie nicht wissen, was passiert ist. Eine zuverlässige API geht deshalb von Anfang an davon aus, dass dieselbe Anfrage zweimal eintreffen kann.

Deshalb erklären wir in diesem Beitrag den Begriff auf konzeptioneller Ebene. Sie finden hier keinen Codeblock, sondern die Logik, die Einsatzgebiete und die Grenzen.

Was ist Idempotenz am Beispiel eines Aufzugknopfs?

Stellen Sie sich den Knopf für das dritte Stockwerk in einem Aufzug vor. Zunächst drücken Sie ihn einmal, und der Aufzug fährt in den dritten Stock. Dann werden Sie ungeduldig und drücken noch fünfmal. Es ändert sich also nichts. Der Aufzug fährt weiterhin nur zu einem Stockwerk, und das Ergebnis bleibt gleich. Somit ist dieser Knopf idempotent.

Nun stellen Sie sich vor, Sie sagen am Kiosk: "Eine Zeitung bitte." Glaubt die Verkäuferin, Sie hätten nichts gesagt, und Sie wiederholen die Bestellung, gehen Sie mit zwei Zeitungen heim. Diese Aktion ist nicht idempotent, denn jede Wiederholung verändert das Ergebnis.

Software liegt in der Praxis zwischen diesen beiden Beispielen. Der Befehl "setze den Bestellstatus auf bestätigt" verhält sich wie der Aufzugknopf. Der Befehl "lege einen Artikel in den Warenkorb" verhält sich dagegen wie die Zeitungsbestellung. Mit dem richtigen Entwurf können Sie allerdings die zweite Variante in die erste verwandeln, und das zeigen wir später.

Außerdem stammt der Begriff aus der Mathematik. Wendet man eine Funktion zweimal an und erhält dasselbe wie nach dem ersten Mal, ist sie idempotent. Zum Beispiel bleibt der Betrag von minus drei immer drei, egal wie oft Sie ihn bilden. Was ist Idempotenz also in der Softwarewelt? Es ist dasselbe Versprechen, angewendet auf Serveroperationen.

Warum entstehen doppelte Abbuchungen überhaupt?

Die Ursache liegt in dem Moment, in dem der Client die Antwort des Servers nicht sieht. Zunächst klickt ein Kunde auf "Bezahlen". Der Server nimmt die Zahlung entgegen und verarbeitet sie dann. Dann geht die Antwort unterwegs verloren, oder das Zeitlimit läuft ab. Der Client glaubt deshalb, die Zahlung sei gescheitert.

An dieser Stelle sind drei Dinge möglich:

  • Die Anwendung sendet die Anfrage automatisch erneut.
  • Der Kunde lädt die Seite neu oder tippt den Button ein zweites Mal an.
  • Ein zwischengeschaltetes Gateway oder ein Load Balancer wiederholt die Anfrage von selbst.

Konkret sieht der Server in allen drei Fällen dieselbe Anfrage zweimal. Erkennt er die Wiederholung nicht, zieht er dem Kunden das Geld doppelt ein. Eine Doppelabbuchung ist daher selten ein zufälliger Fehler. Sie ist das natürliche Ergebnis einer Lücke im Entwurf.

Gefährlich ist vor allem, dass niemand es bemerkt. Währenddessen sieht der Kunde eine Zahlung, der Server aber zwei. Dieser Unterschied fällt daher erst beim Monatsabschluss oder durch eine Beschwerde auf. Das Problem wächst also unbemerkt.

Außerdem schaffen Fehlerseiten des Servers ähnliche Lagen. Wer zum Beispiel einen 502 Bad Gateway Fehler erhält, weiß nicht, ob die Operation tatsächlich stattgefunden hat.

Welche HTTP Methoden sind idempotent?

Zum Glück liefert der HTTP Standard hier einen klaren Rahmen. Nach IETF RFC 9110 gilt eine Methode als idempotent, wenn mehrere identische Anfragen dieselbe beabsichtigte Wirkung haben wie eine einzelne. Laut Standard sind GET, HEAD, OPTIONS und TRACE idempotent, ebenso PUT und DELETE. POST und PATCH gelten dagegen per Definition nicht als idempotent.

Ein Detail ist allerdings wichtig. Denn der Standard spricht von der beabsichtigten Wirkung. Eine Logdatei darf also zusätzliche Zeilen bekommen, und ein zweites DELETE darf "nicht gefunden" melden. Der Endzustand auf dem Server ist trotzdem in beiden Fällen gleich: Der Datensatz ist weg.

Der Standard gibt außerdem Hinweise zu Wiederholungen. Ein Client darf eine idempotente Anfrage automatisch wiederholen, wenn die Verbindung abbricht. Bei einer nicht idempotenten Methode sollte er das nicht tun, solange er nicht sicher weiß, dass die Anfrage in der Praxis idempotent ist. Die Einzelheiten finden Sie im Abschnitt zu idempotenten Methoden in RFC 9110.

Dieses Wissen hilft in der Praxis an zwei Stellen. Erstens wählen Sie beim Entwurf eines Endpunkts die passende Methode. Zweitens entscheiden Sie, welche Anfragen ein Client oder Gateway gefahrlos wiederholen darf. Browser, Gateways und Clientbibliotheken richten sich oft nach dieser Unterscheidung. Eine falsche Methodenwahl kann daher Wiederholungen auslösen, die Sie nicht wollen.

Was ist Idempotenz bei PUT, PATCH und POST im REST Design?

Diese drei Methoden sorgen bei REST Schnittstellen für die meiste Verwirrung. Zunächst ersetzt PUT eine Ressource durch den Inhalt, den Sie senden. Dasselbe PUT fünfmal gesendet hinterlässt die Ressource fünfmal im selben Zustand. Es ist also idempotent.

PATCH dient Teilaktualisierungen, und sein Ergebnis hängt davon ab, wie Sie die Anfrage formulieren. Ein PATCH mit "setze den Namen auf Alex" verhält sich praktisch idempotent. Ein PATCH mit "erhöhe den Zähler um eins" liefert dagegen bei jeder Wiederholung ein anderes Ergebnis. Deshalb stuft der Standard PATCH nicht als idempotent ein und überlässt die Entscheidung dem Entwickler.

POST bedeutet meist "erstelle etwas Neues" oder "starte eine Aktion". Eine Wiederholung erzeugt daher einen weiteren Datensatz. Zahlungen, Bestellungen und Nachrichtenversand laufen daher überwiegend über POST. Genau dort braucht man den Idempotency Key am dringendsten.

Als praktische Regel gilt: Formulieren Sie die Operation möglichst als "schreibe den Zielzustand", ähnlich wie bei PUT. Geht das nicht, ergänzen Sie dann Ihr POST um einen Schlüssel.

Wie unterscheiden sich sicher, idempotent und atomar?

Diese Begriffe verwechselt man häufig, deshalb folgt ein Vergleich. Alle drei betreffen die Zuverlässigkeit, beantworten aber unterschiedliche Fragen.

BegriffFrage dahinterBeispielAchtung
------------
Sicher (safe)Ändert die Anfrage den Zustand auf dem Server?Eine Produktseite lesenJede sichere Methode ist idempotent, umgekehrt gilt das nicht
IdempotentÄndert die Wiederholung das Ergebnis?Bestellstatus auf bestätigt setzenDer Zustand ändert sich einmal, Wiederholungen fügen nichts hinzu
AtomarLäuft die Operation ganz oder gar nicht?Überweisung: ein Konto belasten, ein anderes gutschreibenVerhindert keine Wiederholung, sondern halbe Ausführung
DeterministischLiefert dieselbe Eingabe dieselbe Ausgabe?Eine Funktion zur SteuerberechnungSagt nichts über Nebenwirkungen

Zusammengefasst löst Atomarität das Risiko der halben Ausführung, Idempotenz dagegen das Risiko der Wiederholung. Ein zuverlässiges Zahlungssystem braucht deshalb oft beides. Wie Transaktionen ins größere Bild der Serverseite passen, lesen Sie in unserem Beitrag Was ist ein Backend.

Wie funktioniert ein Idempotency Key?

Für Operationen, die von Natur aus nicht idempotent sind, ist die Lösung eine Kennung an der Anfrage. Zunächst erzeugt der Client für jede logische Operation einen eindeutigen Schlüssel und sendet ihn mit. Sieht der Server den Schlüssel zum ersten Mal, führt er dann die Operation aus und speichert das Ergebnis zusammen mit dem Schlüssel. Kommt derselbe Schlüssel erneut, führt der Server nichts aus und liefert das gespeicherte Ergebnis zurück.

Die offizielle Dokumentation von Stripe beschreibt diesen Ansatz gut. Demnach speichert der Anbieter Statuscode und Inhalt der ersten Anfrage mit einem Schlüssel, und spätere Anfragen mit demselben Schlüssel erhalten diese gespeicherte Antwort. Die Einzelheiten finden Sie in der Stripe Dokumentation zu idempotenten Anfragen.

Entscheidend ist also, dass der Schlüssel die Absicht kennzeichnet und nicht die Anfrage. Der Kunde hat schließlich nur einmal "bezahlen" gesagt. Wie oft diese Absicht über das Netz reist, spielt keine Rolle, denn das Ergebnis muss einmalig sein.

Ein Beispielszenario macht das konkret greifbar. Ein Kunde bestätigt seinen Warenkorb, und die App sendet "Bestellung abschließen" mit einem Schlüssel. Zunächst legt der Server die Bestellung an, doch die Antwort kommt langsam. Dann versucht die App es mit demselben Schlüssel erneut. Weil der Server den Schlüssel kennt, liefert er eine Zusammenfassung der ersten Bestellung, statt eine zweite anzulegen. Der Kunde sieht folglich eine Bestellung, und Ihr Team stellt eine Rechnung aus.

Die HTTP API Arbeitsgruppe der IETF arbeitet zudem an einem Standardheader namens Idempotency-Key. Da es sich noch um einen Entwurf handelt, prüfen Sie den aktuellen Stand auf der IETF Entwurfsseite.

Wie sollte der Client Schlüssel erzeugen und wiederverwenden?

Die Qualität des Schlüssels bestimmt daher die Zuverlässigkeit des Verfahrens. Beachten Sie beim Erzeugen diese Regeln:

  • Nutzen Sie einen zufälligen Wert mit sehr geringer Kollisionswahrscheinlichkeit, etwa eine UUID.
  • Leiten Sie den Schlüssel nie aus persönlichen Daten wie E-Mail oder Telefonnummer ab.
  • Verwenden Sie für jede Wiederholung derselben logischen Operation denselben Schlüssel.
  • Erzeugen Sie einen neuen Schlüssel, sobald der Nutzer eine neue Operation startet.
  • Erzeugen und speichern Sie den Schlüssel, bevor die Operation beginnt, damit Sie auch nach einem Absturz damit weitermachen können.

Der letzte Punkt entfällt in Teams am häufigsten, denn er wirkt unscheinbar. Erzeugen Sie bei jedem Wiederholungsversuch einen neuen Schlüssel, behandelt der Server jede Anfrage als neu, und der Schutz greift gar nicht.

Anbieter setzen außerdem Grenzen, etwa bei Schlüssellänge und Aufbewahrungsdauer. Prüfen Sie die aktuellen Werte in der offiziellen Dokumentation Ihres Anbieters, denn wir nennen hier bewusst keine Zahlen.

Bei mobilen Apps ist die Lage allerdings kniffliger. Zum Beispiel schickt der Nutzer die App in den Hintergrund, die Verbindung wechselt, und das Betriebssystem sendet die Anfrage später erneut. Speichert Ihre App den Schlüssel lokal, kann sie nach einem Neustart dieselbe Operation mit demselben Schlüssel fortsetzen. Der Nutzer startet dieselbe Zahlung somit nicht doppelt.

Wie setzen Sie Idempotenz auf der Serverseite um?

Der Kerngedanke ist einfach: Speichern Sie den Schlüssel, bevor Sie die Operation ausführen, und hängen Sie das Ergebnis an, sobald sie endet. In der Praxis erschweren einige Details die Sache.

Erstens müssen Schlüsseleintrag und Geschäftslogik in derselben Transaktionsgrenze liegen. Sonst geht die Zahlung durch, aber der Eintrag scheitert, oder umgekehrt. Hier hilft eine Eindeutigkeitsbedingung in der Datenbank, denn ein zweiter Versuch, denselben Schlüssel einzutragen, scheitert.

Zweitens denken Sie an gleichzeitige Anfragen. Treffen zwei Anfragen mit demselben Schlüssel im selben Moment ein, sollte eine weiterlaufen, während die andere wartet oder die Antwort "in Bearbeitung" erhält. Ohne Sperre halten sich somit beide für die erste.

Drittens entscheiden Sie, was Sie speichern, denn davon hängt das spätere Verhalten ab. Das Ergebnis erfolgreicher Aufrufe zu speichern ist das Minimum. Bei Fehlern speichern Sie konsistente Ausgänge. Anfragen, die schon vor Beginn der Arbeit an der Validierung scheiterten, speichern Sie dagegen nicht, weil der Nutzer die Eingabe korrigieren und erneut senden können muss.

Dazu kommt die Frage des Geltungsbereichs. Gilt der Schlüssel pro Nutzer oder pro Endpunkt? In der Praxis bilden Nutzer und Operationstyp zusammen den Bereich. So beeinflussen sich zwei Nutzer nicht, die zufällig denselben Schlüssel erzeugen.

Was passiert, wenn derselbe Schlüssel mit anderem Inhalt eintrifft?

Das ist also die am häufigsten übersehene Ecke des Entwurfs. Angenommen, ein Client sendet denselben Schlüssel mit einem anderen Betrag. Was tun Sie? Das Ergebnis der ersten Operation zurückzugeben wäre irreführend, denn der Client könnte glauben, der zweite Betrag sei verbucht.

Robuste Systeme speichern zum Schlüssel einen Fingerabdruck des Anfrageinhalts. Passt eine neue Anfrage nicht zur ersten mit diesem Schlüssel, gibt der Server einen klaren Fehler zurück. Die Stripe Dokumentation nennt dieses Verhalten ausdrücklich: Die Schicht vergleicht eingehende Parameter mit der ursprünglichen Anfrage und meldet bei Abweichung einen Fehler.

Dieses Verhalten erfüllt zudem zwei Aufgaben. Es hilft Entwicklern, versehentliche Wiederverwendung früh zu entdecken. Außerdem verhindert es, dass ein fehlerhafter oder böswilliger Client mit einem alten Schlüssel einen neuen Vorgang durchdrückt.

Welche Antwort sollte der Server auf eine wiederholte Anfrage geben?

Trifft der Server zum zweiten Mal auf einen bekannten Schlüssel, befindet er sich in einer von drei Lagen. Daher braucht jede eine andere Nachricht an den Client.

  • Ist die erste Anfrage abgeschlossen, liefern Sie die gespeicherte Antwort unverändert zurück. Für den Client darf sich also nichts anders anfühlen.
  • Läuft die erste Anfrage noch, geben Sie eine Antwort, die "in Bearbeitung" bedeutet, damit der Client bald erneut fragen kann.
  • Ist der Schlüssel gleich, der Inhalt aber anders, melden Sie den Konflikt offen.

Wichtig ist, dass der Client versteht, was passiert ist, denn sonst muss er raten. Wer stillschweigend einen neuen Datensatz anlegt oder einen vagen Fehler liefert, zwingt Entwickler zum Raten.

Zudem hilft eine Markierung der Antwort. Ein Header, der anzeigt, dass die Antwort aus einem gespeicherten Ergebnis stammt, erleichtert die Arbeit des Supports. Welchen Statuscode Sie wählen, hängt von Ihrem API Vertrag und Ihrem Framework ab. Die Bedeutung der Codes schlagen Sie in RFC 9110 nach.

Schließlich sagen Sie den Clients, wie lange eine gespeicherte Antwort gültig bleibt. Erklärt Ihre Dokumentation Dauer und Verhalten klar, müssen Teams nicht raten. Deshalb ist eine klare Dokumentation oft der günstigste Weg, Fehler zu vermeiden.

Wie arbeiten Zeitüberschreitung und Retry mit Idempotenz zusammen?

Ein Retry ist das automatische Wiederholen einer Anfrage, die gescheitert scheint. Allein ist er gefährlich, denn Sie wissen nicht, ob die erste Anfrage doch geklappt hat. Idempotenz beseitigt dagegen diese Gefahr. Zusammen liefern beide "mindestens einmal senden, höchstens einmal verarbeiten".

Was ist Idempotenz also in einer Wiederholungsschleife? Sie macht die Schleife erst sicher. Ohne sie riskieren Sie Datenverlust oder doppelte Verarbeitung, und beides zugleich vermeiden Sie nicht von allein.

Eine gute Strategie für Wiederholungen besteht aus diesen Teilen:

  • Verwenden Sie bei jedem Versuch denselben Idempotency Key.
  • Zweitens warten Sie nach jedem Fehlschlag länger. Das nennt man Exponential Backoff.
  • Fügen Sie eine kleine zufällige Abweichung hinzu, den sogenannten Jitter, damit nicht tausende Clients gleichzeitig anklopfen.
  • Außerdem legen Sie eine Obergrenze für die Zahl der Versuche fest.
  • Wiederholen Sie nur vorübergehende Fehler, etwa Zeitüberschreitungen und abgebrochene Verbindungen.

Bei dauerhaften Fehlern wie fehlenden Berechtigungen erhöht jeder Versuch dagegen nur die Last. Deshalb ist es wichtig, beide Arten zu unterscheiden.

Reicht es, den Button nach dem Klick zu sperren?

Nein. Den Button nach dem ersten Klick zu sperren ist eine gute Gewohnheit, doch sie mindert nur Wiederholungen in der Oberfläche. Sie stoppt nämlich weder Wiederholungen der Netzwerkschicht noch eine App, die im Hintergrund erneut sendet, noch einen zweiten Browsertab.

Denken Sie deshalb in zwei Schichten. In der Oberfläche sperren Sie den Button und zeigen "wird verarbeitet" an. Auf dem Server sorgen Sie dann mit Idempotenz für den eigentlichen Schutz. Die Oberfläche verbessert das Erlebnis, der Server schützt dagegen die Daten.

Vergessen Sie außerdem das Neuladen nicht. Wer nach dem Absenden eines Formulars den Browser aktualisiert, sendet womöglich dieselbe Anfrage noch einmal. Eine Weiterleitung auf eine eigene Ergebnisseite senkt dieses Risiko, ersetzt den Serverschutz aber nie.

Warum ist Idempotenz für Zahlungs APIs und Bestell APIs so wichtig?

Geldbewegungen lassen sich nämlich am schwersten rückgängig machen. Deshalb heben Zahlungsanbieter Idempotency Keys in ihren offiziellen Dokumenten hervor. Auch Bestellsysteme tragen ähnliche Risiken: doppelte Bestellungen, doppelte Lagerabbuchungen und doppelte Rechnungen.

Betrachten Sie als Beispielszenario einen kleinen Onlineshop. Ein Kunde zahlt per Karte und schließt den 3D Secure Schritt ab, doch das Mobilfunknetz bricht ab, und die Seite erhält keine Antwort. Danach versucht der Kunde es erneut. Ohne Idempotenz entstehen zwei Abbuchungen, danach folgen eine Erstattung, ein Supportverlauf und verlorenes Vertrauen. Mit Idempotenz erhält die zweite Anfrage das gespeicherte Ergebnis, und der Kunde sieht eine Zahlung.

Prüfen Sie bei der Wahl eines Zahlungsanbieters, ob er diese Funktion unterstützt. Allgemeine Kriterien finden Sie in unserem Beitrag zur Auswahl von Zahlungsanbietern für Onlineshops. Bei Problemen im Prüfschritt hilft unser Beitrag, wenn 3D Secure fehlschlägt.

Zudem ist eine gemeinsame Sprache im Team nützlich. Für Produktverantwortliche lautet die kurze Antwort auf die Frage, was ist Idempotenz: Eine Absicht des Kunden führt zu einem Ergebnis. Entwickler machen daraus eine technische Anforderung, und das Testteam macht daraus ein Abnahmeszenario.

Was ist Idempotenz bei Ereignissen und Webhooks?

Nachrichtenwarteschlangen und Webhooks arbeiten meist nach dem Prinzip "mindestens einmal zustellen". Dasselbe Ereignis kann Sie also zweimal erreichen. Das als Fehler zu sehen wäre falsch, denn das System wiederholt absichtlich. Denn ein verlorenes Ereignis ist schlimmer als ein doppeltes.

Daher muss die empfangende Seite idempotent sein. Man nennt dieses Muster einen idempotenten Verbraucher (Idempotent Consumer). Der Ansatz ist einfach: Jedes Ereignis trägt eine eindeutige Kennung, der Verbraucher merkt sich die verarbeiteten Kennungen und ignoriert ein bereits bekanntes Ereignis.

Sendet ein Zahlungsanbieter zum Beispiel die Meldung "Zahlung abgeschlossen" zweimal, setzen Sie die Bestellung nicht zweimal auf "versandbereit". Ereignisbasierte Systeme behandeln wir in unserem Beitrag zu Event Driven Architecture, auch mit Ereigniskennung und Reihenfolge.

Die Reihenfolge ist dagegen ein eigenes Thema. Ereignisse treffen nicht immer in der gesendeten Reihenfolge ein. Der Verbraucher darf deshalb nicht zulassen, dass ein altes Ereignis einen neueren Zustand überschreibt. Ein Zeitstempel oder eine Versionsnummer senkt dieses Risiko und ergänzt die Idempotenz.

Wie entwerfen Sie Operationen, die von Natur aus idempotent sind?

Sie müssen allerdings nicht immer Schlüssel speichern. Manchmal können Sie die Operation von Anfang an idempotent entwerfen. Der Kniff besteht darin, den Befehl als Zielzustand statt als Änderung zu formulieren.

EntwurfIdempotent?Grund
---------
"Erhöhe das Guthaben um 50"NeinJede Wiederholung fügt eine weitere Erhöhung hinzu
"Setze das Guthaben auf 150"JaEine Wiederholung schreibt denselben Zielwert
"Lege einen Artikel in den Warenkorb"NeinJede Wiederholung erhöht die Menge
"Setze die Menge des Artikels auf 2"JaDie Zielmenge ist festgelegt
"Erstelle einen neuen Datensatz"NeinJede Wiederholung erzeugt eine neue Kennung
"Erstelle oder aktualisiere den Datensatz mit dieser Kennung"JaDie Kennung steht fest, also bleibt ein Datensatz

Dieser Ansatz verlangt, dass der Client die Kennung selbst erzeugt. Vergibt der Server sie, bekommen die erste Anfrage und die Wiederholung unterschiedliche Kennungen. Eine kleine Entwurfsentscheidung schafft somit ein großes Sicherheitsnetz.

Manche nennen das auch Zielzustandsmodell. Solche Befehle zu wiederholen braucht keinen zusätzlichen Schutz. Natürlich passt nicht jede Aufgabe in diese Form, denn eine echte Abbuchung ist von Natur aus schrittweise. Dann greifen Sie wieder zur Schlüsselmethode.

Wie hilft Idempotenz in Microservices und verteilten Abläufen?

In Systemen, in denen mehrere Dienste zusammenarbeiten, laufen Aufrufe als Kette. Der Bestelldienst ruft zum Beispiel den Lagerdienst auf, und der Lagerdienst ruft den Versanddienst auf. Läuft ein Dienst in der Mitte in ein Zeitlimit, ist unklar, welche Schritte fertig wurden.

In dieser Unsicherheit ist der sicherste Weg, jeden Schritt der Kette idempotent zu machen. Der koordinierende Dienst kann dann den unsicheren Schritt erneut senden. War der Schritt schon fertig, ändert sich dann nichts. War er es nicht, schließt er jetzt ab.

Ausgleichsaktionen folgen ebenso demselben Prinzip. Ein Erstattungsschritt, der zweimal läuft, darf nicht zwei Erstattungen bedeuten. Deshalb tragen auch Erstattungsanfragen eigene Schlüssel.

Den größeren Rahmen des Dienstentwurfs finden Sie in unserem Vergleich von Python und Go für Backend und Microservices. Dort geht es um die Sprachwahl und nicht um Idempotenz, und dieser Beitrag schließt die Lücke.

Welche Grenzen und Risiken hat Idempotenz?

Allerdings löst Idempotenz nicht jedes Problem. Kennen Sie diese Grenzen:

  • Nebenwirkungen: Ein Schlüssel schützt nicht automatisch Wirkungen, die externe Systeme erreichen, etwa E-Mail oder Benachrichtigungen. Binden Sie diese an denselben Schlüssel.
  • Aufbewahrung: Schlüsseleinträge leben nicht ewig. Nach Ablauf der Frist gilt eine Wiederholung eventuell als neue Anfrage.
  • Speicherkosten: Für jeden Schlüssel eine Antwort zu halten braucht zusätzlichen Platz und Pflege.
  • Falsche Sicherheit: Entwickler vernachlässigen womöglich Zeitlimits und Fehlerbehandlung, weil Idempotenz existiert.
  • Semantische Fallen: Mit PUT sagen Sie "ersetze alles". Senden zwei Clients zeitgleich verschiedene Werte, gewinnt der letzte Schreiber. Das ist idempotent, aber trotzdem unerwünscht.

Idempotenz ist also ein Sicherheitsnetz und kein Ersatz für korrekte Geschäftslogik. Enthalten die gespeicherten Einträge zudem personenbezogene Daten, klären Sie die Aufbewahrung mit Ihrer eigenen Rechtsberatung. Dieser Beitrag ist keine Rechtsberatung.

Diese Grenzen zu kennen, setzt daher die richtige Erwartung. Wer fragt, was ist Idempotenz, bekommt die ehrliche Antwort: Es ist ein Entwurfsprinzip, das den Schaden von Wiederholungen begrenzt, wenn Netze und Clients unzuverlässig sind. Es ist kein Produkt, das Fehler auf magische Weise beseitigt.

Welche Fehler passieren bei der Einführung von Idempotenz am häufigsten?

Die Fehler, die wir immer wieder sehen, entstehen aus kleinen Details. Achten Sie auf diese Punkte:

  • Der Schlüssel entsteht bei jedem Wiederholungsversuch neu.
  • Der Schlüsseleintrag liegt in einer anderen Transaktion als die Geschäftslogik.
  • Das Team speichert nur erfolgreiche Antworten und nie Fehler.
  • Niemand vergleicht den Anfrageinhalt mit dem Schlüssel.
  • Der Schlüssel stammt von einem Zähler, den jeder erraten kann.
  • Der Webhook Handler hält keine eindeutige Ereigniskennung fest.
  • E-Mail und Benachrichtigungen an Fremdsysteme bleiben ungeschützt.

Jeder Punkt wirkt für sich allein klein. Zusammen zeigen sie sich jedoch als Doppelabbuchung, doppelte Rechnung oder wiederholte Benachrichtigung. Daher empfehlen wir, die Checkliste zum Teil Ihrer Code Reviews zu machen.

Wie testen Sie eine idempotente API?

Erstens zeigen Tests, dass der Mechanismus wirklich funktioniert. Probieren Sie diese Szenarien der Reihe nach:

  1. Senden Sie dieselbe Anfrage zweimal mit demselben Schlüssel und prüfen Sie, ob die zweite Antwort der ersten gleicht.
  2. Kontrollieren Sie, dass in der Ergebnistabelle nur ein Datensatz entsteht.
  3. Senden Sie mit demselben Schlüssel anderen Inhalt und prüfen Sie, ob der Server einen klaren Fehler liefert.
  4. Senden Sie zwei Anfragen mit demselben Schlüssel gleichzeitig und prüfen Sie, dass nur eine verarbeitet wird.
  5. Trennen Sie mitten in der Operation gezielt die Verbindung und wiederholen Sie danach mit demselben Schlüssel.
  6. Beobachten Sie das Verhalten nach Ablauf der Aufbewahrungsfrist.

Gibt es Probleme, dann müssen Sie die Protokolle prüfen. Unser Beitrag zu Debugging Techniken für Entwickler hilft in dieser Phase. Wiederholte Anfragen in den Zugriffsprotokollen Ihres Servers erkennen Sie außerdem mit unserer Logfile Analyse.

Außerdem verwenden Sie in Testumgebungen kein echtes Geld. Nutzen Sie lieber die Testmodi der Zahlungsanbieter, damit Sie Wiederholungsszenarien gefahrlos probieren können. Binden Sie die Tests zudem in Ihre kontinuierliche Integration ein, dann bemerken Sie sofort, wenn eine Änderung den Schutz bricht.

Was ist Idempotenz bei Serverless und warum zählt sie dort mehr?

Cloud Funktionen kann die Plattform automatisch wiederholen. Selbst wenn Sie nichts tun, kann eine Funktion also mit derselben Eingabe zweimal laufen. Deshalb ist idempotenter Code in der Serverless Architektur nahezu Pflicht.

Kaltstart und Kosten haben wir im Beitrag Was ist Serverless behandelt. Hier ergänzen wir nur einen Punkt: Läuft eine Funktion in ein Zeitlimit, kann die Plattform nicht wissen, ob die Arbeit fertig ist, und versucht es erneut. Ihre Funktion muss das daher aushalten.

Marketing Integrationen verhalten sich ebenso. Doppelt eintreffende Ereignisse im Conversion Tracking führen zu Doppelzählung. Im Beitrag zu Meta Pixel und Conversions API mit doppelten Events sehen Sie dieselbe Logik als Deduplizierung über eine Ereigniskennung.

Welche Checkliste hilft Entwicklern und Unternehmen in der Praxis?

Die folgende Liste nützt dem technischen Team und den Produktverantwortlichen gleichermaßen:

  1. Listen Sie jeden POST Ablauf auf, der Geld, Lagerbestand oder Datensätze erzeugt.
  2. Wählen Sie für jeden Ablauf einen Idempotency Key oder einen von Natur aus idempotenten Entwurf.
  3. Erzeugen Sie den Schlüssel im Client vor Beginn der Operation und behalten Sie ihn über alle Versuche.
  4. Schreiben Sie den Schlüsseleintrag in derselben Transaktionsgrenze wie die Geschäftslogik.
  5. Liefern Sie einen klaren Fehler, wenn derselbe Schlüssel mit anderem Inhalt kommt.
  6. Setzen Sie eine Sperre oder eine Eindeutigkeitsbedingung gegen zwei gleichzeitige Anfragen.
  7. Halten Sie in Webhook und Warteschlangen Verbrauchern die Ereigniskennung fest.
  8. Nutzen Sie bei Wiederholungen Exponential Backoff und eine begrenzte Zahl von Versuchen.
  9. Dokumentieren Sie Aufbewahrungsdauer und Datenschutzanforderungen.
  10. Machen Sie aus den oben genannten Testszenarien automatische Tests.

Fragen Sie auf der Unternehmensseite Anbieter, ob ihre Dokumentation Idempotenz unterstützt. Diese Frage gehört deshalb vor einer Vertragsunterschrift zu den wertvollsten.

Füllen Sie diese Liste nicht einmal aus und vergessen sie dann. Gehen Sie sie erneut durch, sobald Sie einen Endpunkt ergänzen oder den Anbieter wechseln. Idempotenz ist weniger ein Feature, das man einmal baut, als eine Gewohnheit, die man bei jeder Änderung pflegt.

Wann sollten Sie Unterstützung von Fachleuten holen?

Bei einem kleinen internen Werkzeug brauchen Sie womöglich nicht alle genannten Schutzmaßnahmen. Nehmen Sie jedoch Zahlungen an, verwalten Sie Lagerbestand oder binden Sie Drittsysteme an, gehört Idempotenz an den Anfang des Entwurfs. Nachträglich kostet sie weit mehr, als Dubletten in bestehenden Daten zu bereinigen.

Schauen Sie zunächst auf das Risiko. Bedeutet ein Fehler, dass Kunden zu viel zahlen, Bestand verloren geht oder eine rechtliche Pflicht entsteht, bauen Sie den Schutz zuerst. Sind die Folgen klein und umkehrbar, genügt dann eventuell eine leichtere Lösung. Die Frage, was ist Idempotenz für Ihre eigenen Abläufe, zu beantworten ist der gesündeste Weg zur Entscheidung.

Wir von Talha Aslan und Team unterstützen Integration und API Entwurf mit unserer individuellen Softwareentwicklung. Die Risikokarte eines bestehenden Systems zu zeichnen gehört dazu.

Denken Sie schließlich daran, dass sich Standards und Anbieterdokumente mit der Zeit ändern. Die hier erklärten Konzepte bleiben allerdings bestehen. Prüfen Sie Bezeichnungen, Grenzwerte und Einzelheiten aber immer in der offiziellen Dokumentation.

Häufig gestellte Fragen

Ist Idempotenz dasselbe wie eine idempotente API?
Idempotenz ist der Name einer Eigenschaft, eine idempotente API ist dagegen eine Schnittstelle, die diese Eigenschaft bietet. Das heißt, eine idempotente API liefert dasselbe Ergebnis, wenn sie dieselbe Anfrage mehrfach erhält. Sie erreicht das entweder durch die Natur der Methode oder durch einen Mechanismus wie den Idempotency Key. Das eine beschreibt das Konzept, das andere das System.
Kann eine POST Anfrage idempotent sein?
Ja, aber nicht von Haus aus. RFC 9110 stuft POST nicht als idempotent ein, weil jeder Aufruf einen neuen Datensatz erzeugen kann. Sendet der Client jedoch einen eindeutigen Idempotency Key und speichert der Server ihn, verhält sich der POST Ablauf praktisch idempotent. Die meisten Zahlungsanbieter empfehlen diesen Weg in ihrer eigenen Dokumentation.
Warum gilt GET als idempotent?
GET dient allein dem Lesen von Informationen und soll den Zustand des Servers nicht ändern. RFC 9110 zählt GET zu den sicheren Methoden, und jede sichere Methode ist auch idempotent. Löscht Ihre API aber bei einem GET einen Datensatz oder erhöht einen Zähler, verletzen Sie den Standard, und Systeme wie Caches machen Probleme.
Wie lange sollte ich einen Idempotency Key aufbewahren?
Die Dauer hängt davon ab, wie lange eine Wiederholung realistisch eintreffen kann, und von Ihrer Speicherkapazität. Der Schlüssel sollte mindestens so lange leben, wie ein Client sinnvoll weiter versuchen kann. Zahlungsanbieter nennen ihre Aufbewahrung in der Dokumentation, prüfen Sie dort den aktuellen Wert. Beachten Sie auch Datenschutzregeln für Antworten mit personenbezogenen Daten.
Verhindert Idempotenz Doppelabbuchungen vollständig?
Nein, allein reicht sie nicht, doch sie ist eine der stärksten Abwehrmaßnahmen. Eine Doppelabbuchung kann trotzdem passieren, wenn der Schlüssel falsch entsteht, sich bei jedem Versuch ändert oder getrennt von der Geschäftslogik liegt. Gibt ein Kunde zwei getrennte Bestellungen auf, sind das außerdem zwei Absichten. Überwachung, Abgleich und Tests bleiben nötig.
Braucht man Idempotenz nur bei Zahlungssystemen?
Nein. Sie hilft überall, wo Wiederholung ein Risiko ist, etwa bei Bestellungen, Lagerbestand, E-Mail Versand, Webhooks, Warteschlangen und Cloud Funktionen. Geld ist das sichtbarste Beispiel. Doch auch eine doppelte Benachrichtigung oder ein zweimal angelegtes Support Ticket schadet dem Kundenerlebnis, deshalb lohnt die Frage bei jeder Integration.
  • Idempotenz
  • idempotente API
  • Idempotency Key
  • HTTP Methoden
  • Retry
  • Doppelbuchung
  • API Design
Teilen:
Talha Aslan

Google Partner und Experte für digitales Marketing. Seit 2012 praktisch in SEO, Google Ads, Webdesign und E-Commerce Projekten; jeder Beitrag hier stammt aus dieser Erfahrung.

Nächstes Projekt

Sprechen wir über Ihr Projekt.

Ihre Anfrage geht direkt an Talha Aslan und Team: Strategie von Talha, Umsetzung durch ein erfahrenes Team. Das Erstgespräch ist kostenlos, wir hören zu und melden uns mit einer klaren Roadmap.