Begriff
Idempotency
Warum wichtig?
Dieser Begriff ist ein Knoten im SengakujiWorks-Wissensnetz. Nutze Level 0 für die erste Einordnung, Level 1 für Praxis, Level 2 für technische Struktur und Level 3 für Grenzen, Fallstricke und Expertenkontext.
Ein kompliziertes Wort für ein einfaches Konzept. Idempotenz bedeutet: Es ist egal, wie oft du den Knopf drückst, das Ergebnis ist das gleiche wie beim ersten Mal. Beispiel Fahrstuhlknopf: Egal ob du 1x oder 20x drückst, der Fahrstuhl kommt einfach nur. Er kommt nicht "20x schneller" oder "20 Fahrstühle". Das ist idempotent. Gegenbeispiel Online-Shopping "Kaufen": Wenn du 2x klickst (weil Internet langsam ist), kaufst du 2 Toaster? Das wäre nicht idempotent (und sehr schlecht). In der IT müssen wir Systeme so bauen, dass sie Wiederholungen (Retries) verkraften, ohne Chaos anzurichten.
Merksatz: Die Eigenschaft einer Operation, bei mehrfacher Ausführung dasselbe Ergebnis zu liefern wie bei einer einzigen Ausführung, ohne zusätzliche Seiteneffekte zu erzeugen.
Bei HTTP Methoden:
GETist idempotent (Lesen ändert nix).PUTist idempotent (User A überschreiben -> User A überschreiben -> Inhalt gleich).DELETEist idempotent (Löschen -> Löschen -> Weg ist weg).POSTist NICHT idempotent (Neuer User -> Neuer User -> 2 User).
Lösung für POST (z. B. Payment):
Der Client sendet eine einzigartige ID (Idempotency-Key: uuid-123).
Der Server speichert: "ID uuid-123 habe ich um 12:00 Uhr schon bearbeitet."
Kommt die ID nochmal, macht er nichts und sendet nur die alte Quittung zurück.
1. At-Least-Once Delivery
In Message Queues (Kafka, RabbitMQ) passiert es oft, dass Nachrichten doppelt ankommen ("At-Least-Once"). Der Consumer stürzt nach der Arbeit ab, bevor er "Done" sagen konnte. Der Broker sendet die Nachricht nochmal an einen anderen Consumer. Wenn dein Consumer nicht idempotent ist ("Email senden"), bekommt der Kunde 2 Emails. Idempotenz ist der einzige Weg, um in verteilten Systemen "Exactly-Once Processing" zu simulieren.
2. Implementierung (Optimistic Locking)
In Datenbanken erreicht man Idempotenz oft durch Versionierung.
UPDATE accounts SET balance = balance - 10 WHERE id = 1 AND version = 5.
Wenn zwei Requests gleichzeitig kommen:
Erster: version=5 -> version=6. Success.
Zweiter: version=5. Fails (Row not found / Version Mismatch).
Das verhindert "Lost Updates" und macht die Operation sicher wiederholbar (Retry Logic muss dann neu lesen).
3. Side Effects
Reine Idempotenz bezieht sich auf den Zustand des Servers.
Aber was ist mit Seiteneffekten? (Logfiles, Metriken).
Ein zweiter DELETE Request ändert zwar die DB nicht (User bleibt gelöscht), aber er schreibt vielleicht einen neuen Log-Eintrag ("Error 404 Not Found").
Das ist streng genommen eine Verletzung der Idempotenz, wird aber in der Praxis akzeptiert.
Wichtig ist der "Business State".
1. Idempotency Keys und Race Conditions (Stripe Pattern)
Einen Request idempotent zu machen, ist bei Zahlungssystemen hochkomplex (Concurrency-Hölle).
Szenario: Request A und Retry Request B (wegen Timeouts in der App) schlagen auf gleicher Millisekunde im Payment-Gateway auf.
PostgreSQL fragt "Existiert UUID X schon?". Transaktion A sagt Nein, Transaktion B sagt Nein. Beide buchen 100 Euro ab.
Das Stripe-API-Pattern löst das hard-core auf DB-Level: Der Idempotency-Key wird vor der Business-Logik blind mit einer harten Datenbank-Constraint (UNIQUE) als "locked" weggeschrieben (INSERT INTO idempotency_log). Schlägt B fast zeitsynchron auf, verletzt das INSERT eine Row-Lock Isolation, B bricht ab und wartet passiv. Ist A nach 2 Sekunden fertig, updatet A den Key mit dem JSON-HTTP-Response-Blob. Danach purzelt der Waiter B heraus, liest das fertige Blob direkt vom Key und antwortet dem Client ohne jede Backend-Logik-Ausführung.
2. State-Machine vs API-Idempotenz
Gute Idempotenz erfordert oft puren Zustand (State Machines) anstelle von prozeduralem Code.
Ein REST Call POST /cancel_subscription darf nicht "Ziehe -1 vom Abo Status ab" machen. Er muss sagen: target_state: CANCELLED.
Sollte die Subskription bereits von jemand anderem gecancelled worden sein (Admin-UI), darf der Call keinen 400 Error ("Bereits gecancelled!") werfen. Wahre verteilte API-Idempotenz verlangt hier stoisch einen 200 OK. Der Request-Intend (Soll-Zustand "Gelöscht") stimmt mit der Reality-Datenbank exakt überein. Es ist irrelevant, ob exakt dieser spezifische Request die Status-Mutation des SQL-Feldes triggern musste oder historisch wer anders.
3. Message Deduplication und Exactly-Once Processing
Kafka verspricht "Exactly-Once", was physikalisch gegen das Two-Generals Problem verstößt.
Man baut es durch eine extrem tiefe Kopplung der Idempotenz mit dem Consumer-Commit-Protokoll um.
Kafka injiziert eine pure Sequence-ID von Producer-Seite her (Sequence = 5) zusammen mit einer Producer-UID (PID). Kafka lehnt PID X / Seq 5 eiskalt via Broker Cache ab, wenn es diese Seq bereits kommittiert im Log persistiert hat (Producer Retry Idempotency). Erst durch dieses Transaktions-Log-Pipelining – die Idempotenz sitzt tiefster im Datei-Append-Level – wird "At-Least-Once Delivery" mathematisch zwingend zu einem "Exactly-Once Processing" gefesselt.
Quick-Check
Warum Ansible?
Ansible liebt Idempotenz. Ein Playbook ("Installiere Nginx") kann ich 100x aufrufen. Beim 1. Mal installiert es. Beim 2. bis 100. Mal sagt es "OK (Changed=0)". Normale Bash-Skripte (apt install) sind oft nicht idempotent und werfen Fehler.Ist
x = x + 1idempotent?Nein! 1x ausgeführt: x=2. 2x ausgeführt: x=3. Ergebnis ändert sich.x = 5ist idempotent. Egal wie oft, x bleibt 5.Retries ohne Idempotenz?
Tödlich. "Network Timeout" heißt nicht "nicht passiert". Es heißt "Vielleicht passiert, vielleicht nicht". Ohne Idempotenz kannst du keinen automatischen Retry machen, weil du riskierst, Daten zu korrumpieren.