Przejdź do głównej zawartości

Ponawianie i idempotencja

Sieci zawodzą – zwłaszcza na urządzeniach mobilnych. Wszystkie SDK Frontmail automatycznie ponawiają nieudane żądania i robią to bezpiecznie: ponowiona wysyłka nigdy nie skutkuje zduplikowanym e-mailem ani podwójnym pobraniem kredytu.

Sytuacja Ponawiane?
Błąd sieci (offline, DNS, zerwane połączenie) ✓
Timeout (timeoutMs, domyślnie 15 s na próbę) ✓
Odpowiedzi 5xx ✓
429 rate_limited ✓ – czeka zgodnie z Retry-After (jeśli to 60 s lub mniej)
Błędy 4xx – walidacja, uwierzytelnianie, origin, CAPTCHA ✗ – ponowienie by nie pomogło
Blokady po stronie klienta (blockHeadless, blockList, limitRate) ✗

Domyślna polityka: 3 ponowienia po pierwszej próbie, wykładniczy backoff zaczynający się od 300 ms z pełnym jitterem, najwyżej 10 s między próbami. Skonfigurujesz ją opcją retry:

init({ publicKey: 'pk_4f2a…', retry: { retries: 5, baseDelayMs: 500, maxDelayMs: 20_000 } });
init({ publicKey: 'pk_4f2a…', retry: false }); // wyłączenie

Każde logiczne wywołanie send() dostaje losowy UUID jako Idempotency-Key, a wszystkie ponowienia tej wysyłki używają tego samego klucza. Frontmail pamięta klucze na serwerze przez 24 godziny:

  • ten sam klucz z tą samą treścią zwraca pierwotną odpowiedź (to samo message_id) i niczego nie wysyła ponownie,
  • ten sam klucz z inną treścią kończy się błędem 409 idempotency_conflict.

Jeśli więc pierwsza próba faktycznie dotarła do Frontmail, a zgubiła się tylko odpowiedź, ponowienie po prostu dostaje pierwotny wynik.

Przekaż jawny klucz, gdy może się powtórzyć sam wyzwalacz – webhook doręczony dwa razy, zadanie, które się restartuje, użytkownik wysyłający formularz dwa razy w dwóch kartach:

// @frontmail/node
await frontmail.send({ templateId: 'tpl_receipt', params, idempotencyKey: `receipt-${order.id}` });
// @frontmail/browser – opcje są ostatnim argumentem
await send('svc_01J9…', 'tpl_receipt', params, { idempotencyKey: `receipt-${order.id}` });

Klucz może mieć do 255 znaków. Dla każdego odrębnego e-maila używaj nowego klucza – ponowne użycie klucza dla innego e-maila zwróci błąd zamiast go wysłać.

Przy REST API wysyłasz nagłówek samodzielnie:

Okno terminala
curl https://api.frontmail.dev/v1/send \
-H 'Idempotency-Key: receipt-A-1042' \
-H 'Authorization: Bearer sk_…' \
-H 'Content-Type: application/json' \
-d '{ "template_id": "tpl_receipt", "template_params": { "order_id": "A-1042" } }'

Przy wysyłkach zbiorczych ustaw idempotencyKey (w REST API idempotency_key) osobno dla każdej wiadomości.

Gdy API zwróci 202, ponawianie doręczenia to już zadanie Frontmail: moduł wysyłki ponawia przejściowe błędy dostawcy z backoffem, przy błędach uwierzytelniania lub trwałych błędach przełącza się na usługę zapasową, a gdy usługa nie działa – wstrzymuje wiadomości. Twój kod nie musi nic robić – jeśli potrzebujesz, sprawdź wynik przez getStatus() albo w Historii.