<EbeneX/>
Web Praxis · Updated 3. März 2026

Idempotenz

Definition

Eine Operation ist idempotent, wenn sie beliebig oft ausgeführt werden kann und immer dasselbe Ergebnis liefert wie beim ersten Mal – entscheidend für robuste APIs und verteilte Systeme.

Fortgeschritten 3 Min. Lesezeit EN: Idempotency

Einfach erklärt

In verteilten Systemen passieren Netzwerkfehler. Eine Anfrage wird gesendet, aber die Antwort kommt nie an – war die Anfrage erfolgreich oder nicht? Die sichere Lösung: einfach nochmal senden. Aber nur, wenn die Operation idempotent ist.

Nicht idempotent: POST /orders – zweimal gesendet = zwei Bestellungen
Idempotent: PUT /orders/123/status mit {"status": "shipped"} – zehnmal gesendet = Status ist „shipped”

Das ist der Kern: Idempotente Operationen können sicher wiederholt werden, ohne unerwünschte Nebeneffekte.

At-least-once vs. Exactly-once

In verteilten Systemen gibt es drei Delivery-Garantien:

GarantieBedeutungRisiko
At-most-onceHöchstens einmal geliefertDatenverlust möglich
At-least-onceMindestens einmal geliefertDuplikate möglich
Exactly-onceGenau einmal geliefertSehr aufwändig, selten wirklich garantiert

At-least-once + Idempotenz = sicheres System: Wenn Duplikate sicher ignoriert werden, ist At-least-once ausreichend und viel einfacher als Exactly-once.

Technischer Deep Dive

HTTP-Methoden im Überblick

MethodeIdempotentSicherTypische Verwendung
GETDaten lesen
PUTRessource ersetzen
DELETERessource löschen
POSTRessource erstellen
PATCH⚠️Teilweise aktualisieren

Idempotency Key implementieren

import json
import redis
from fastapi import FastAPI, Header, HTTPException

app = FastAPI()
cache = redis.Redis()

@app.post("/payments")
async def create_payment(
    payment: PaymentRequest,
    idempotency_key: str = Header(..., alias="Idempotency-Key")
):
    cache_key = f"idem:{idempotency_key}"

    # Bereits verarbeitet? → Gespeichertes Ergebnis zurückgeben
    cached = cache.get(cache_key)
    if cached:
        return json.loads(cached)

    # Noch nicht verarbeitet → Zahlung durchführen
    try:
        result = await process_payment(payment)
    except Exception as e:
        # Fehler NICHT cachen – Retry soll erneut versuchen
        raise HTTPException(status_code=500, detail=str(e))

    # Ergebnis 24h cachen (nur bei Erfolg)
    cache.setex(cache_key, 86400, json.dumps(result))
    return result

Idempotente Datenbankoperationen

-- ❌ Nicht idempotent: Jedes Mal wird ein neuer Datensatz erstellt
INSERT INTO orders (user_id, product_id, amount)
VALUES (123, 456, 99.99);

-- ✅ Idempotent: Nur einfügen wenn noch nicht vorhanden
INSERT INTO orders (id, user_id, product_id, amount)
VALUES ('ord_abc123', 123, 456, 99.99)
ON CONFLICT (id) DO NOTHING;

-- ✅ Idempotent: Upsert – einfügen oder aktualisieren
INSERT INTO order_status (order_id, status, updated_at)
VALUES ('ord_abc123', 'shipped', NOW())
ON CONFLICT (order_id) DO UPDATE SET
  status = EXCLUDED.status,
  updated_at = EXCLUDED.updated_at;

Idempotente Webhook-Verarbeitung

processed_events = set()  # In Production: Redis oder DB

@app.post("/webhooks/stripe")
async def handle_stripe_webhook(request: Request):
    payload = await request.body()
    sig = request.headers.get("Stripe-Signature")

    # Signatur verifizieren
    event = stripe.Webhook.construct_event(payload, sig, WEBHOOK_SECRET)

    # Bereits verarbeitet?
    if event.id in processed_events:
        return {"status": "already_processed"}

    # Verarbeiten
    if event.type == "payment_intent.succeeded":
        await fulfill_order(event.data.object)

    processed_events.add(event.id)
    return {"status": "ok"}

Stripe-Beispiel

curl https://api.stripe.com/v1/charges \
  -H "Idempotency-Key: a8f3b2c1-4d5e-6f7a-8b9c-0d1e2f3a4b5c" \
  -d amount=2000 \
  -d currency=eur
# Zweiter Aufruf mit gleichem Key → gleiche Antwort, keine zweite Zahlung

Wann ist Idempotenz besonders wichtig?

  • Zahlungen: Doppelte Abbuchungen sind kritisch
  • E-Mail-Versand: Doppelte Willkommens-Mails sind ärgerlich
  • Lagerbestand: Doppeltes Reduzieren führt zu negativem Bestand
  • Webhook-Handler: Webhooks werden oft mehrfach gesendet (Retry-Logik des Senders)
  • Message Queues: Kafka, RabbitMQ liefern At-least-once – Consumer müssen idempotent sein

Idempotenz ist wie ein Lichtschalter: Wenn das Licht an ist und du drückst zehnmal auf 'An', bleibt es an – das Ergebnis ändert sich nicht. Aber 'Licht umschalten' ist nicht idempotent: Jedes Drücken ändert den Zustand.

Idempotente Operationen können sicher wiederholt werden – bei Netzwerkfehlern kein Problem

HTTP: GET, PUT, DELETE sind idempotent – POST in der Regel nicht

Idempotency Keys ermöglichen idempotente POST-Anfragen

Zahlungsabwicklung

Doppelte Zahlungen verhindern: Gleiche Anfrage zweimal gesendet → Zahlung nur einmal ausgeführt

Webhook-Verarbeitung

Webhooks können mehrfach gesendet werden – idempotente Handler verarbeiten sie nur einmal

Retry-Logik

Bei Netzwerkfehlern kann eine Anfrage sicher wiederholt werden, ohne Duplikate zu erzeugen

Welche HTTP-Methoden sind idempotent?

GET: Ja (liest nur). PUT: Ja (setzt Ressource auf definierten Zustand). DELETE: Ja (Ressource ist danach weg, egal wie oft). PATCH: Nicht zwingend (hängt von der Implementierung ab). POST: Nein (erstellt jedes Mal eine neue Ressource).

Was ist ein Idempotency Key?

Eine eindeutige ID, die der Client mit einer Anfrage mitschickt. Der Server speichert das Ergebnis der ersten Anfrage mit dieser ID. Bei einer Wiederholung gibt er das gespeicherte Ergebnis zurück, ohne die Operation erneut auszuführen. Stripe und andere Payment-APIs nutzen dieses Muster.

Was ist der Unterschied zwischen idempotent und sicher (safe)?

Eine 'sichere' Operation verändert den Zustand nicht (GET, HEAD). Eine idempotente Operation kann den Zustand verändern, aber mehrfaches Ausführen hat denselben Effekt wie einmaliges (PUT, DELETE). Alle sicheren Operationen sind auch idempotent, aber nicht umgekehrt.

Dein persönliches Share-Bild für Instagram – 1080×1080px, bereit zum Posten.