Idempotente Wiederholungsversuche in einer SMS-API gestalten, um doppelte Sendungen zu vermeiden
Praxisleitfaden zum Umgang mit Timeouts und mehrdeutigen Ergebnissen beim SMS-Versand, ohne aus einem technischen Wiederholungsversuch eine zweite Nachricht zu machen. Mit Idempotenzschlüsseln, persistenten Zuständen, Abgleich über Callbacks oder DLR und speziellen Kontrollen für OTP.

Warum ein Timeout nicht beweist, dass die SMS nicht akzeptiert wurde
Ein Timeout bedeutet, dass der Client innerhalb der konfigurierten Zeit keine Antwort erhalten hat. Für sich allein beweist es nicht, dass der Server die Anfrage nicht erhalten, nicht verarbeitet oder die Nachricht nicht zur späteren Zustellung akzeptiert hat.
Bei einer HTTP-Operation können sämtliche Bytes der Anfrage übertragen und die entfernte Nachricht erstellt worden sein, bevor die Antwort verloren geht. Es kann jedoch auch passieren, dass die Verbindung ausfällt, bevor der Anbieter die Anfrage erhält. Aus Sicht der Client-Anwendung können beide Szenarien identisch aussehen: Es liegt keine nutzbare Antwort vor.
Daher sollte ein Timeout nach Beginn der Übertragung als mehrdeutiges Ergebnis eingestuft werden. Die sofortige Wiederholung einer Nachrichtenerstellung mit einer neuen Identität kann zu einer zweiten SMS führen, obwohl die erste bereits existiert oder akzeptiert wurde.
- Behandeln Sie das Ausbleiben einer Antwort nicht als endgültige Ablehnung.
- Unterscheiden Sie, sofern Ihre Bibliothek und Telemetrie dies ermöglichen, zwischen einem Fehler vor dem Senden der Anfrage, während der Übertragung und nach dem Senden.
- Gestalten Sie den Ablauf so, dass dieselbe Geschäftsabsicht abgefragt, abgeglichen oder wiederholt werden kann, ohne eine neue Operation zu erstellen.

Das operative Risiko doppelter Nachrichten
Ein Duplikat verursacht nicht nur zusätzliche Kosten. In einem OTP-Ablauf kann es Nutzerinnen und Nutzer verwirren, wenn sie unterschiedliche Codes erhalten – insbesondere dann, wenn das System beim Erzeugen eines neuen Codes den vorherigen ungültig macht. Bei betrieblichen Warnmeldungen können zwei Hinweise wiederholte Maßnahmen auslösen. Bei transaktionalen Benachrichtigungen kann die empfangende Person die zweite Nachricht als Fehler oder Betrugsversuch interpretieren.
Prävention darf nicht mit wahlloser Unterdrückung verwechselt werden. Zwei tatsächlich unterschiedliche Geschäftsaktionen können zwei SMS an dieselbe Nummer mit ähnlichem Inhalt erfordern. Ziel ist es, die technische Wiederholung derselben Absicht zu deduplizieren, nicht rechtmäßige, einwilligungsbasierte und notwendige Kommunikation zu verhindern.
- Ein technischer Wiederholungsversuch muss die Identität der ursprünglichen Absicht beibehalten.
- Eine neue OTP-Challenge, eine neue Operation oder eine bewusst neue Version der Nachricht benötigt eine neue Identität.
- Die Deduplizierung muss auf ein dokumentiertes Zeitfenster und eine dokumentierte Semantik angewendet werden, nicht nur auf die Zielnummer.

Definieren Sie ein Zustandsmodell, das Annahme und Zustellung trennt
Ein Mindestmodell muss unterscheiden, was Ihre Anwendung weiß, was der Anbieter bestätigt und was später vom Zustellzyklus gemeldet wird. Die Annahme durch einen Anbieter oder einen vorgelagerten Carrier entspricht nicht zwangsläufig der endgültigen Zustellung an den Empfänger.
Eine praktikable interne Abfolge kann Folgendes umfassen: erstellt, Versandversuch läuft, an Anbieter gesendet, Annahme bestätigt, Ergebnis ausstehend und Endergebnis. Die genaue Benennung ist weniger wichtig als persistente, auditierbare und eindeutige Übergänge.
Das Endergebnis kann eine gemeldete Zustellung, eine Nichtzustellung, einen endgültigen Fehler oder das Ablaufen eines Abgleichzeitfensters darstellen. Wenn Sie DLR oder Callbacks erhalten, speichern Sie neben dem konsolidierten Zustand auch das ursprüngliche Ereignis und dessen Empfangszeitpunkt.
- Erstellt: Die Geschäftsabsicht ist bereits persistent gespeichert, aber der Versand wurde noch nicht gestartet.
- Versandversuch läuft: Ein identifizierbarer Versuch wurde reserviert, bevor die Verbindung geöffnet wird.
- Annahme bestätigt: Der Anbieter hat geantwortet und eine Bestätigung oder Kennung gemäß seinem Vertrag zurückgegeben.
- Ergebnis ausstehend: Es liegt eine Annahme oder ein mehrdeutiges Ergebnis vor, und es wird auf eine Abfrage, einen Callback, einen DLR oder einen anderen Abgleich gewartet.
- Endergebnis: Der Ablauf hat nach den dokumentierten Regeln für diese Integration einen terminalen Zustand erreicht.
Verwenden Sie einen Idempotenzschlüssel für eine konkrete Absicht
Ein Idempotenzschlüssel ermöglicht es einer API, die Wiederholung einer vorherigen Anfrage von einer neuen Operation zu unterscheiden. Damit dies funktioniert, muss der Client beim Wiederholen exakt derselben Geschäftsabsicht denselben Schlüssel wiederverwenden.
Der Schlüssel sollte nicht nur die Telefonnummer repräsentieren. Derselbe Empfänger kann mehrere legitime Mitteilungen erhalten. Er muss mit einem stabilen Ereignis verknüpft sein: beispielsweise mit der internen Kennung einer Benachrichtigung, einer konkreten OTP-Challenge, dem Empfänger, dem SMS-Kanal und der zu sendenden Inhaltsversion.
Wenn der Anbieter ein Idempotenz-Token unterstützt, halten Sie sich an dessen Vertrag: Format, Position in der Anfrage, Umgang mit abweichenden Parametern, Umfang der Deduplizierung und Aufbewahrungszeitraum. Wenn er dies nicht unterstützt, muss die Idempotenz hauptsächlich im eigenen System kontrolliert werden; Wiederholungsversuche nach mehrdeutigen Ergebnissen erfordern dann noch mehr Vorsicht.
- Erzeugen Sie den Schlüssel einmal pro Absicht, nicht einmal pro Netzwerkversuch.
- Speichern Sie den Schlüssel vor dem Remote-Aufruf persistent.
- Speichern Sie einen Fingerabdruck oder eine Version der relevanten Parameter, um zu erkennen, ob jemand versucht, den Schlüssel für eine andere Operation wiederzuverwenden.
- Verwenden Sie den Schlüssel nicht erneut für eine neue OTP-Challenge oder eine unabhängige Geschäftskommunikation.
- Gehen Sie nicht davon aus, dass alle Anbieter über dieselbe Dauer oder mit derselben Semantik deduplizieren.
Speichern Sie die Absicht persistent, bevor Sie HTTP oder SMPP aufrufen
Die Persistierung muss vor der Netzwerkoperation erfolgen. Wenn Sie zuerst die API aufrufen und erst danach einen Datensatz speichern, kann eine Unterbrechung zwischen beiden Aktionen eine entfernte Nachricht ohne lokale Absicht hinterlassen, über die sie nachverfolgt oder abgeglichen werden kann.
Erstellen Sie in einer lokalen Transaktion den Versanddatensatz, weisen Sie die interne Kennung, den Idempotenzschlüssel, die zur Reproduktion der Anfrage erforderlichen Parameter und den Zustand erstellt zu. Anschließend kann ein Versandprozess diesen Datensatz übernehmen, den Versuch als laufend markieren und den Anbieter aufrufen.
Nach Erhalt einer gültigen Antwort speichern Sie die entfernte Kennung und die Bedeutung der Antwort persistent. In SMPP liefert eine erfolgreiche Antwort auf submit_sm eine vom SMSC zugewiesene message_id; diese Kennung muss zur Korrelation späterer Operationen und Zustellbestätigungen erhalten bleiben.
- Interne Kennung der Absicht.
- Idempotenzschlüssel und Fingerabdruck der Anfrage.
- Ziel und Inhalt oder ein sicherer Verweis auf dessen autorisierte Version.
- Zeitstempel für Erstellung, Beginn und Ende jedes Versuchs.
- Vom Anbieter oder SMSC zurückgegebene Kennung, sofern vorhanden.
- Aktueller Zustand, Verlauf der Zustandsübergänge und Grund für jeden terminalen Zustand.
Klassifizieren Sie Ergebnisse, bevor Sie über Wiederholungsversuche entscheiden
Eine sichere Wiederholungsstrategie basiert nicht auf dem Prinzip „Jeder Fehler wird erneut gesendet“. Sie muss endgültige Antworten, wiederherstellbare Fehler und mehrdeutige Ergebnisse trennen. Die konkreten Kategorien müssen aus dem Vertrag des jeweiligen Anbieters und dem verwendeten Protokoll abgeleitet werden.
Endgültige Antworten erfordern in der Regel, den Vorgang zu beenden oder die Kontrolle an den Geschäftsprozess zurückzugeben: beispielsweise ungültige Zugangsdaten, ungültige Parameter, ein nicht unterstütztes Format oder eine als ungültig deklarierte Zieladresse. Wiederholen ohne Änderung der Ursache erhöht nicht die Zuverlässigkeit und kann unnötigen Datenverkehr verursachen.
Wiederherstellbare Fehler können vorübergehende Nichtverfügbarkeit, Ratenbegrenzung oder ausdrücklich dokumentierte temporäre Netzwerkfehler umfassen. In SMPP signalisiert ESME_RTHROTTLED, dass erlaubte Nachrichtenlimits überschritten wurden; die angemessene Reaktion besteht darin, den Druck zu reduzieren und kontrolliert zu warten, nicht in einer Schleife erneut zu senden.
Mehrdeutige Ergebnisse umfassen Timeouts, Verbindungsabbrüche und verlorene Antworten nach Beginn des Sendens. Sie dürfen nicht automatisch als wiederherstellbare Fehler behandelt werden, da der Anbieter die Nachricht möglicherweise akzeptiert hat.
- Endgültig: Beenden Sie den Vorgang, protokollieren Sie die Ursache und korrigieren Sie die Anfrage oder den Ablauf, bevor Sie eine neue Absicht erstellen.
- Wiederherstellbar: Planen Sie einen begrenzten Wiederholungsversuch mit demselben Idempotenzschlüssel.
- Mehrdeutig: Fragen Sie nach, wenn dies möglich ist, warten Sie auf ein Abgleichsignal und verwenden Sie dieselbe Identität nur erneut, wenn der Anbieter kompatible Deduplizierung bietet.
- Throttling: Wenden Sie Ratenkontrolle und progressive Wartezeiten an; bündeln Sie Wiederholungsversuche nicht im selben Zeitpunkt.
Wenden Sie Grenzen, progressive Wartezeiten und ein Gültigkeitsfenster an
Ein Wiederholungsversuch muss durch die Anzahl der Versuche, die Gesamtdauer und die Gültigkeit der Geschäftsabsicht begrenzt sein. Progressive Wartezeiten verhindern eine Konzentration von Anfragen nach einem Vorfall oder einer Ratenbegrenzung. Sie können kontrollierte Zufallsvariation ergänzen, damit viele Worker nicht synchron wiederholen.
Es gibt keine universelle Anzahl von Versuchen und keine Wartezeit, die für alle Routen und Anwendungsfälle gültig ist. Definieren Sie diese anhand der Kritikalität der Nachricht, des dokumentierten Verhaltens des Anbieters, der vertraglichen oder technischen Ratenlimits und der Lebensdauer des Inhalts.
Die Richtlinie muss stoppen, wenn ein Endzustand erreicht wird, das geschäftliche Zeitfenster abläuft oder das Wiederholungsbudget überschritten wird. Ein Wiederholungsversuch nach Ablauf des Nutzens der Nachricht kann schlimmer sein als ein Fehler: Eine verspätete Warnung oder ein abgelaufenes OTP erfüllt den ursprünglichen Bedarf nicht.
- Legen Sie eine maximale Anzahl von Versuchen und ein Gesamtzeitlimit pro Absicht fest.
- Vergrößern Sie das Intervall zwischen Wiederholungsversuchen bei temporären Fehlern oder Throttling.
- Nutzen Sie eine verzögerte Warteschlange, statt den Hauptablauf durch aktives Warten zu blockieren.
- Protokollieren Sie jede Entscheidung: warum erneut versucht wurde, wie lange gewartet wurde und welche Regel den Vorgang beendet hat.
- Machen Sie aus einer technischen Wiederherstellung keinen unbegrenzten Versand.
Behandeln Sie OTP als Fall für Sicherheit und Nutzererlebnis
Bei OTP lautet die Absicht nicht „einen Text an eine Nummer senden“, sondern einen Code zu übermitteln, der einer konkreten Challenge zugeordnet und zeitlich begrenzt gültig ist. Der Idempotenzschlüssel muss dieser Challenge entsprechen, nicht einer einzelnen HTTP-Anfrage.
Das System muss eindeutig festlegen, ob ein neuer Verifizierungsversuch dieselbe Challenge wiederverwendet oder eine neue erstellt. Wenn ein neuer Code erstellt wird und der vorherige aktiv bleibt, kann der Nutzer mehrere gültige Codes erhalten. Wenn der vorherige ungültig gemacht wird, kann eine verspätete SMS einen Code enthalten, der nicht mehr funktioniert. Beide Entscheidungen betreffen Produkt und Sicherheit, müssen jedoch mit der Versandrichtlinie konsistent sein.
Das Wiederholungsfenster muss enden, bevor die Challenge abläuft. Es muss außerdem mit einer beim Anbieter konfigurierten Gültigkeitsdauer für die Warteschlange abgestimmt werden. Es ist nicht angemessen, die Zustellung eines OTP weiter zu versuchen, sobald es nicht mehr verifiziert werden kann.
- Ordnen Sie jedes OTP einer persistenten Challenge-Kennung zu.
- Wiederholen Sie denselben Versand mit demselben Schlüssel, wenn es sich um dieselbe Absicht handelt.
- Dokumentieren Sie, wann ein neuer Code generiert wird und was mit den vorherigen Codes geschieht.
- Beenden Sie Wiederholungsversuche und ausstehende Sendungen, wenn die Challenge abläuft.
- Messen Sie Duplikate, Verzögerungen und Abbrüche, ohne mehr personenbezogene Daten als nötig zu speichern.
Häufige Fragen
Bedeutet ein Timeout in einer SMS-API, dass die Nachricht nicht gesendet wurde?
Nein. Es kann bedeuten, dass die Verbindung ausfiel, bevor der Anbieter die Anfrage erhielt. Es kann aber auch bedeuten, dass der Anbieter sie erhielt und verarbeitete, während die Antwort verloren ging oder verzögert wurde. Behandeln Sie dies als mehrdeutiges Ergebnis, bis ein Abgleich möglich ist.
Was sollte ein Idempotenzschlüssel für SMS enthalten?
Er sollte eine konkrete Geschäftsabsicht identifizieren. Er kann mit einer internen Ereignis- oder OTP-Challenge-Kennung, dem Empfänger, dem Kanal und der Inhaltsversion verknüpft sein. Er darf nicht nur aus der Zielnummer bestehen und nicht bei jedem Wiederholungsversuch neu erzeugt werden.
Sollte ich einen Throttling-Fehler wiederholen?
Er kann für einen kontrollierten Wiederholungsversuch infrage kommen, wenn der Vertrag des Anbieters ihn als temporär einstuft. Wenden Sie Ratenkontrolle, progressive Wartezeiten und Grenzen an. Senden Sie nicht sofort oder unbegrenzt erneut.
Bestätigt ein DLR immer den Empfang auf dem Telefon?
Nicht unbedingt. Die Bedeutung jedes Status hängt vom Vertrag und von den Informationen ab, die in der Zustellkette verfügbar sind. Sie müssen zwischen Annahme durch den Anbieter, Weiterleitung an einen Carrier, empfangenem DLR und jeder gemeldeten Zustellbestätigung unterscheiden. Ein DLR darf nicht über seine dokumentierte Semantik hinaus interpretiert werden.
Ersetzen Callbacks die Antwort auf die Nachrichtenerstellung?
Nein. Die synchrone Antwort und Callbacks erfüllen unterschiedliche Funktionen. Einige Anbieter senden keinen Callback für den Anfangszustand. Daher müssen Sie die Antwort auf die Erstellung persistent speichern und spätere Änderungen über Callbacks, Abfragen oder DLR abgleichen.
Was ist zu tun, wenn der Anbieter keine Idempotenzschlüssel unterstützt?
Kontrollieren Sie die Absicht und die Zustände im eigenen System, bevor Sie den Anbieter aufrufen. Priorisieren Sie bei einem mehrdeutigen Timeout die Abfrage über verfügbare Kennungen und den Abgleich von Ereignissen. Wenn kein Mechanismus für Remote-Deduplizierung oder Abfragen vorhanden ist, dokumentieren Sie diese Einschränkung und gehen Sie beim Erstellen einer zweiten Anfrage besonders restriktiv vor.
Verwendete Quellen
- RFC 9110: HTTP SemanticsIETF / RFC Editor
- SMPP Protocol Specification v3.4, Issue 1.2SMPP Developers Forum
- Messages resourceTwilio
- Outbound Message Status in Status CallbacksTwilio
- Messaging ServicesTwilio
- Cloud Control API ReferenceAmazon Web Services
- AWS Well-Architected Framework: Reliability PillarAmazon Web Services