Сервис повторяет операции по тексту ошибки: какое свойство дизайна ошибки позволит заменить такой механизм?
Ошибка должна иметь стабильную машиночитаемую классификацию, например признак «операцию допустимо повторить», доступный через errors.Is или errors.As. Текст сообщения следует использовать только для диагностики, а не для принятия программных решений.
Изначально интерфейс error в Go предоставлял главным образом текстовое описание через метод Error. Этого достаточно для журналирования, но недостаточно для надежной классификации причин без привязки к формулировкам сообщений.
Механизм оборачивания ошибок и функции errors.Is и errors.As позволяют сохранять контекст и извлекать семантические свойства ошибки через цепочку оберток. Это поддерживает разделение между сообщением для человека и контрактом для машинной обработки.
Повтор операции безопасен не для каждой ошибки. Сетевой разрыв или временная недоступность зависимости могут допускать повтор, тогда как ошибка валидации, отказ в доступе или нарушение бизнес-правила обычно повтором не исправляются.
Проверка текста ненадежна: сообщение может измениться, локализоваться или быть дополнено контекстом. Слишком агрессивный повтор способен создать дублирующие записи, усилить нагрузку на зависимость и увеличить задержки; отсутствие повтора при временном сбое ухудшает надежность сервиса.
Нужно определить отдельную семантическую категорию ошибки, например ErrRetryable, и сделать ее доступной через errors.Is. Конкретная причина при этом должна сохраняться через Unwrap, чтобы диагностика и другие проверки не потеряли исходную ошибку.
Внешний код проверяет errors.Is(err, ErrRetryable), а не текст. Цепочка сохраняет и категорию, и исходную причину: ее можно дополнительно исследовать через errors.Is или errors.As.
Классификация должна быть консервативной: неизвестную ошибку обычно безопаснее считать неповторяемой. При этом признак «можно повторить» не означает «нужно повторять»: решение также зависит от идемпотентности операции, лимита попыток, экспоненциальной задержки, отмены контекста и ограничений зависимости.
Не следует автоматически обозначать как повторяемые все ошибки транспорта. Например, успешная запись могла завершиться ошибкой ответа, поэтому повтор небезопасной операции способен выполнить действие дважды. Для таких случаев нужны идемпотентный ключ, проверка состояния операции или иной протокол согласования.
Платежный сервис получает временный сбой от провайдера. Первый вариант — искать в сообщении слова вроде «timeout»: он прост, но ломается при изменении текста и не учитывает ошибки, обернутые несколькими слоями. Второй вариант — проверять конкретный тип драйвера: это точнее, но связывает бизнес-слой с реализацией провайдера.
Выбран вариант с доменной категорией повторяемости, которую адаптер провайдера назначает на границе системы. Сервис проверяет категорию через errors.Is, ограничивает число попыток и повторяет только идемпотентные запросы; для неповторяемых операций используется ключ идемпотентности. В результате замена драйвера не меняет логику сервиса, а диагностическая причина остается доступной в журнале.
1. Достаточно ли одного признака «повторяемая ошибка», чтобы безопасно выполнить повтор?
Нет. Этот признак описывает свойства сбоя, но не гарантирует безопасность повторного действия. Нужно отдельно учитывать идемпотентность операции, состояние контекста, число уже выполненных попыток, дедлайн и возможную частичную обработку запроса.
2. Следует ли возвращать признак повторяемости из каждой функции слоя приложения?
Нет, если слой не обладает достаточной информацией. Низкоуровневый сетевой адаптер может сообщить, что сбой похож на временный, но решение о повторе должно принимать владелец операции, знающий ее семантику и допустимый побочный эффект.
3. Почему нельзя сделать любую неизвестную ошибку повторяемой по умолчанию?
Потому что неизвестная причина может означать ошибку данных, нарушение контракта или уже выполненное действие, после которого потерян только ответ. Повтор в такой ситуации способен привести к дублированию, перегрузке системы или скрытию дефекта; безопаснее повторять только явно классифицированные ошибки и ограничивать политику повторов.