Как обработать отрицательную скорость, возвращаемую микросервисом
Что проверяют
Как вы обращаетесь с данными от чужого сервиса: доверяете или проверяете на границе, и отличаете ли ошибку в данных от законного значения. Следом обычно спрашивают: «а если отрицательная скорость здесь нормальна, например при движении назад?»
Как отвечать
Начните с вопроса, а не с if speed < 0: что такое скорость в этом домене. Это может быть модуль (минус означает баг), проекция с направлением (минус законен) или разница двух замеров с шумом датчика (тогда -0.3 это погрешность). От ответа зависит решение, и его стоит зафиксировать в контракте API: схема OpenAPI с minimum: 0 или явное описание знака.
Дальше защита на своей стороне:
- валидация на границе: ответ парсится в модель Pydantic с полем
speed: float = Field(ge=0). Невалидные данные падают сValidationErrorв одном месте, а не расползаются по бизнес-логике; - политика для плохого значения: отклонить весь ответ, отбросить одну точку, заменить на
Noneи показать «нет данных» или обрезать до нуля, если это известный шум. Молча подставлять ноль без договорённости нельзя; - ответ вызывающему: если вы сами API, то внятная ошибка, например 502 при некорректном ответе апстрима, а не 500 со стектрейсом;
- наблюдаемость: структурный лог с идентификатором запроса и значением, счётчик невалидных ответов в метриках и алерт на рост. Одно значение это шум, тысяча в минуту это инцидент у соседей;
- тесты:
pytest.raises(ValidationError)на отрицательное значение и отдельный тест на граничный ноль.
Параллельно сообщите команде сервиса-источника: исправлять данные нужно там, где они возникают, а ваша проверка остаётся страховкой.
Где спотыкаются
Молча делают abs(speed) или max(speed, 0). Ошибка в источнике скрыта, отчёты врут, и никто не узнает, что сервис сломан.
Не уточняют смысл величины и сразу объявляют минус ошибкой, хотя в домене он может быть законным.
Проверяют значение в десятке мест вместо одной модели на границе. Проверки расходятся, где-то их забывают, и плохие данные всё равно просачиваются. Сюда же тест через try/except без pytest.raises: он проходит, даже если исключение вообще не выброшено.