Jeśli wywołanie Durable Object kończyło się błędem sieciowym, programista często musiał wcześniej decydować, czy wysłać je ponownie. Od 5 listopada 2026 roku część takich prób wykonuje runtime Cloudflare: automatycznie ponawia określone nieudane wywołania fetch() i RPC przez stub. Kluczowe pytanie dotyczące kodu aplikacji jest teraz bardziej precyzyjne: czy daną metodę można bezpiecznie wykonać drugi raz?
Odpowiedź zależy od tego, w którym miejscu połączenie zostało przerwane. Runtime automatycznie ponawia niektóre wywołania, domyślnie chroniąc przed podwójnym wykonaniem. Gdy nie wiadomo, czy żądanie zostało dostarczone, używa tego samego identyfikatora żądania, a obiekt odrzuca ponowną próbę, jeśli otrzymał już pierwszą. Metoda jawnie oznaczona jako retryable() działa inaczej: może zostać uruchomiona ponownie, nawet jeśli pierwsza próba dotarła już do obiektu. Dlatego takie oznaczenie jest odpowiednie tylko dla operacji, których powtórzenie jest bezpieczne zarówno dla stanu, jak i skutków ubocznych.
Co dokładnie ponawia runtime
Jak wynika z ogłoszenia Cloudflare z 5 listopada, ponawianie obejmuje wywołania fetch() i RPC kierowane do Durable Object przez Workera lub inny Durable Object. W przypadku wywołań przez stub domyślnie wykonywana jest pierwsza próba i maksymalnie cztery ponowienia; nowe próby nie są rozpoczynane później niż 10 sekund od rozpoczęcia wywołania.

Warunkiem jest błąd z właściwością .retryable. Na przykład żądanie mogło nie dotrzeć do obiektu, ponieważ ten był ponownie uruchamiany lub przenoszony. Runtime może też ponowić próbę, jeśli połączenie zostało zerwane i nie wiadomo, czy obiekt zdążył przyjąć żądanie. Jeśli obiekt już je otrzymał, ponowienie z tym samym identyfikatorem zostaje odrzucone. Runtime nie ponawia błędów zgłoszonych przez kod Durable Object, błędów z właściwością .overloaded ani odpowiedzi HTTP, takich jak 500: to odpowiedź obsługi żądania, a nie błąd dostarczenia.
Dlaczego ponowne dostarczenie nie oznacza ponowienia operacji
Samo ponowienie transmisji żądania nie oznacza, że metoda zostanie uruchomiona drugi raz. Gdy wynik jest niepewny, runtime wysyła żądanie z tym samym identyfikatorem; jeśli obiekt przyjął pierwotną próbę, odrzuca ponowienie. W zwykłym trybie zapobiega to ponownemu wykonaniu metody, na przykład ponownemu pobraniu opłaty lub utworzeniu wpisu wskutek pojedynczego błędu sieciowego.

Granica się zmienia, gdy metoda zostaje oznaczona za pomocą retryable() z cloudflare:durable-objects. Wówczas obiekt może ponownie wykonać metodę, jeśli pierwsza próba mogła się już rozpocząć. Cloudflare podaje dwa przykłady: przypisanie produktowi określonej liczby sztuk jest idempotentne; zwiększenie tej liczby o jeden — nie. Powtórzenie pierwszej czynności ustawia tę samą wartość, a powtórzenie drugiej dodaje kolejną sztukę.
Należy sprawdzić nie tylko końcowy stan magazynu, lecz także wszystkie skutki działania metody. Jeśli ponowienie tworzy kolejną płatność, wysyła wiadomość lub uruchamia działanie zewnętrzne, identyczny stan wewnątrz Durable Object nie sprawia, że ponowienie jest bezpieczne. Oznaczenie jest odpowiednie wtedy, gdy powtórzenie nie zmienia znaczenia wyniku ani nie duplikuje skutków ubocznych.
Kiedy jawna idempotencja jest przydatna
Ustawienie wartości, zapis migawki stanu lub aktualizacja pola do znanej wartości często dają ten sam rezultat po ponowieniu. W przypadku takich metod retryable() może pozwolić wywołaniu zakończyć się powodzeniem po zerwaniu połączenia, które nastąpiło już po rozpoczęciu przetwarzania.
Operacje „dodaj”, „utwórz kolejny”, „pobierz opłatę” i „wyślij” zwykle wymagają innego zabezpieczenia. Zanim zezwolisz na ponowne uruchomienie, upewnij się, że operacja biznesowa rozpoznaje duplikaty albo jest zbudowana tak, by ponowienie nie powodowało drugiego skutku. Sama nazwa funkcji niczego nie gwarantuje: sprawdź wszystkie zmiany stanu i działania zewnętrzne wykonywane w metodzie.
retryable() ma wąskie zastosowanie: zezwala na ponowne wykonanie, gdy nie wiadomo, czy pierwsze wywołanie dotarło do celu. Nie zmienia zestawu błędów, na które reaguje runtime, ani liczby prób. Oznaczenie dotyczy funkcji; nadpisana lub opakowana wersja metody nie dziedziczy go automatycznie, jeśli również nie zostanie jawnie oznaczona.
Co sprawdzić w działającym już projekcie
Najbardziej prawdopodobnym miejscem do przeglądu są własne pętle ponawiania wokół wywołań Durable Objects. Teraz każda taka próba może obejmować ponowienia wykonywane przez runtime, więc łączna liczba wywołań może być większa niż wynikałoby to z ustawień samej aplikacji. Cloudflare zaleca zmniejszenie liczby własnych prób albo ustawienie maxRetries: 0 dla stubów, jeśli ponawianiem zarządza kod aplikacji.
Limity dla konkretnego stuba można ustawić podczas wywołania get() lub getByName(). Parametr maxRetries określa od zera do dziesięciu ponowień po pierwszej próbie; timeoutMs — czas, po którym nie są już rozpoczynane kolejne próby, od 500 do 60 000 milisekund. Ustawienia te dotyczą wywołań przez dany stub. Funkcje retryable() i obiekt retry wymagają Wrangler 4.158.0 lub nowszego.
Przydatny przegląd kodu obejmuje trzy pytania dotyczące każdego wywołania: czy może ono wielokrotnie zmieniać stan; czy ponowi zewnętrzne skutki uboczne; czy aplikacja ma własną politykę ponawiania. Następnie zdecyduj, czy dany stub powinien używać wartości domyślnych, czy własnych limitów. W przypadku metod idempotentnych osobno rozważ jawne oznaczenie; dla pozostałych zachowaj zabezpieczenie i sprawdź obsługę błędu, gdy wynik pierwszej próby jest nieznany.
Wniosek: odpowiedzialność przesuwa się na granicę metody
Automatyczne ponawianie usuwa część logiki sieciowej z kodu aplikacji, ale decyzja, czy wolno ponowić wykonanie, nadal zależy od operacji. Runtime może bezpiecznie ponowić dostarczenie i zatrzymać się, jeśli nie wie, czy wywołanie zostało wykonane. Programista może zezwolić na ponowne wykonanie metody, jawnie potwierdzając, że nie duplikuje ona zmian stanu ani skutków ubocznych.
Dlatego tę aktualizację warto rozumieć jako zmianę kontraktu między warstwą transportową a obsługą żądania. Najpierw sprawdź własne pętle ponawiania i możliwość powielania skutków ubocznych, a następnie skonfiguruj limity dla odpowiednich stubów. W ten sposób wbudowana odporność na krótkotrwałe awarie łączy się z kontrolą nad operacjami, w których drugie wykonanie ma realny koszt.