Если вызов Durable Object завершился сетевым сбоем, разработчику раньше часто приходилось решать, стоит ли отправлять его ещё раз. С 5 ноября 2026 года часть таких повторов выполняет runtime Cloudflare: он автоматически повторяет определённые неудачные вызовы fetch() и RPC через stub. Для прикладного кода ключевой вопрос теперь точнее: может ли конкретный метод безопасно выполниться второй раз?
Ответ зависит от того, где оборвалась связь. Runtime автоматически повторяет некоторые вызовы, сохраняя защиту от двойного выполнения по умолчанию. При неопределённой доставке он использует тот же идентификатор запроса, и объект отклоняет повтор, если уже получил первую попытку. Явно помеченный retryable() метод получает другое поведение: он может запуститься снова, даже если первая попытка уже дошла до объекта. Поэтому пометка подходит только для операций, повтор которых безопасен и для состояния, и для побочных эффектов.
Что именно повторяет runtime
Согласно объявлению Cloudflare от 5 ноября, повторы распространяются на вызовы fetch() и RPC к Durable Object, сделанные Worker или другим Durable Object. Для вызовов через stub по умолчанию предусмотрены первая попытка и до четырёх повторов; новые попытки не начинаются позднее чем через 10 секунд после старта вызова.

Условие — ошибка с признаком .retryable. Например, запрос мог не достичь объекта, потому что тот перезапускался или перемещался. Runtime также может повторить попытку, если соединение оборвалось и нельзя определить, успел ли объект принять запрос. Если объект уже получил запрос, повтор с тем же идентификатором отклоняется. Runtime не повторяет ошибки, выброшенные кодом Durable Object, ошибки с .overloaded и HTTP-ответы вроде 500: это ответ обработчика, а не ошибка доставки.
Почему повтор доставки не равен повтору операции
Повтор передачи запроса сам по себе не означает второй запуск метода. При неопределённом результате runtime отправляет запрос с тем же идентификатором; если объект принял исходную попытку, он отклоняет повтор. Это предотвращает повторное выполнение метода в обычном режиме, например повторное списание или создание записи из-за одного сетевого сбоя.

Граница меняется, когда метод помечен через retryable() из cloudflare:durable-objects. Тогда объекту разрешено повторно выполнить метод, если первая попытка могла уже начаться. Cloudflare приводит два примера: присвоить товару заданное количество — идемпотентно; увеличить количество на единицу — нет. Повтор первого действия устанавливает то же значение, повтор второго добавляет ещё одну единицу.
Проверять нужно не только итоговое состояние хранилища, но и все эффекты метода. Если повтор создаёт ещё один платёж, отправляет сообщение или запускает внешнее действие, одинаковое состояние внутри Durable Object не делает повтор безопасным. Пометка подходит, когда повтор не меняет смысл результата и не дублирует побочные эффекты.
Где полезна явная идемпотентность
Установка значения, запись снимка состояния или обновление поля до известного значения часто дают одинаковый результат при повторе. Для таких методов retryable() может позволить вызову завершиться успешно после обрыва связи, случившегося уже после начала обработки.
Операции «прибавить», «создать ещё одну», «списать» и «отправить» обычно требуют другой защиты. Прежде чем разрешить повторный запуск, убедитесь, что бизнес-операция распознаёт дубликаты или устроена так, что повтор не создаёт второго эффекта. Само имя функции ничего не гарантирует: проверяйте все изменения состояния и внешние действия внутри метода.
У retryable() узкая роль: он разрешает повтор выполнения, когда нельзя определить, дошёл ли первый вызов. Он не меняет перечень ошибок, на которые runtime реагирует, и не увеличивает число попыток. Флаг относится к функции; переопределённая или обёрнутая версия метода автоматически его не наследует, если её тоже явно не отметить.
Что проверить в уже работающем проекте
Самое вероятное место для ревизии — собственные циклы повторов вокруг вызовов Durable Objects. Теперь каждая такая попытка может включать повторы runtime, поэтому суммарное число обращений окажется больше, чем задаёт только приложение. Cloudflare советует сократить собственное число попыток или задать maxRetries: 0 для stub, если повторами управляет ваш код.
Для конкретного stub лимиты задаются при вызове get() или getByName(). Параметр maxRetries задаёт от нуля до десяти повторов после первой попытки; timeoutMs — интервал, после которого новые попытки уже не стартуют, от 500 до 60 000 миллисекунд. Эти настройки применяются к вызовам через данный stub. Возможности retryable() и объекта retry требуют Wrangler 4.158.0 или новее.
Полезная ревизия состоит из трёх вопросов для каждого вызова: может ли он менять состояние более одного раза; повторит ли он внешние побочные эффекты; есть ли у приложения собственная политика повторов. Затем решите, должен ли данный stub использовать значения по умолчанию или собственные лимиты. Для идемпотентных методов можно отдельно оценить явную отметку; для остальных оставьте защиту и проверьте обработку ошибки, когда результат первой попытки неизвестен.
Следствие: ответственность перемещается к границе метода
Автоматический повтор убирает часть сетевой логики из прикладного кода, однако решение о допустимости повторного выполнения остаётся свойством операции. Runtime может безопасно повторить передачу и остановиться, если не знает, выполнился ли вызов. Разработчик может разрешить повтор метода, явно подтвердив, что он не дублирует изменения состояния или побочные эффекты.
Поэтому обновление стоит читать как изменение контракта между транспортным уровнем и обработчиком. Сначала проверьте собственные retry-циклы и повторяемость побочных эффектов; затем настройте лимиты на нужных stubs. Так встроенная устойчивость к кратким сбоям сочетается с контролем над операциями, где второй запуск имеет реальную цену.