Приведи пример бага из-за которого нельзя сделать релиз
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Пример критического бага, блокирующего релиз
Один из наиболее показательных примеров — несовместимость данных между микросервисами после миграции схемы базы данных, которая не была выявлена на тестовых стендах из-за различий в конфигурациях.
Контекст и воспроизведение
В проекте использовалась распределённая система: сервис A (пользователи) и сервис B (транзакции). Сервис B получал данные через асинхронную очередь (RabbitMQ) и кэшировал их в своей локальной базе. Для повышения производительности, в сервисе A провели миграцию: расширили таблицу users, добавив поле currency (VARCHAR(3)). Обновили код сервиса A и отправили его на тестирование. На тестовых стендах (которые использовали синхронные вызовы между сервисами) всё работало корректно. Однако в продакшене сервис B, не обновлённый до новой версии, продолжил получать сообщения от сервиса A через очередь, но не мог десериализовать обновлённую структуру сообщения, содержащую новое поле.
// Сообщение ДО миграции (версия v1)
{
"user_id": 123,
"full_name": "Иван Иванов"
}
// Сообщение ПОСЛЕ миграции сервиса A (версия v2)
{
"user_id": 123,
"full_name": "Иван Иванов",
"currency": "USD" // Новое поле
}
Код сервиса B (на языке Python с использованием Pydantic) ожидал только поля user_id и full_name:
from pydantic import BaseModel
class UserMessage_v1(BaseModel):
user_id: int
full_name: str
# Поля 'currency' нет
def process_message(raw_data: dict):
try:
message = UserMessage_v1(**raw_data) # Ошибка валидации при получении v2
save_to_cache(message)
except ValidationError as e:
logger.error(f"Invalid message format: {e}")
# Сообщение уходит в Dead Letter Queue, обработка прерывается
Почему это блокирует релиз
- Нарушение критической бизнес-логики: Транзакции пользователей перестали обрабатываться, что привело к финансовым потерям и жалобам клиентов.
- Каскадный эффект: Ошибка в одном сервисе вызвала остановку работы зависимой системы.
- Сложность и риск hotfix: Потребовалось бы:
* Экстренный откат сервиса A к предыдущей версии (но сообщения новой структуры уже могли находиться в очередях).
* Или срочное развертывание обновлённого сервиса B (что эквивалентно незапланированному релизу всей системы).
* Очистка очередей и восстановление данных, что могло занять часы.
- Нарушение SLA: Система стала недоступна для ключевой функции, что неприемлемо для клиентов.
Корневые причины и выводы для процесса
Этот баг возник не только из-за ошибки в коде, но и из-за фундаментальных пробелов в процессе:
- Отсутствие контрактов (схем) данных между сервисами и контроля их версионирования (например, через Apache Avro или Protobuf).
- Неполное тестирование интеграции: На стендах использовалась прямая синхронная интеграция (HTTP), в то время как продакшен задействовал асинхронные очереди. Среды тестирования не соответствовали продакшену.
- Нарушение принципа обратной и прямой совместимости (Backward/Forward Compatibility): Новые версии сервиса-отправителя должны были быть совместимы со старыми версиями сервиса-получателя. Следовало реализовать "мягкий" деплой:
* Сначала добавить в сервис B обработку нового поля как необязательного (forward compatible).
* Затем выпустить сервис B в продакшен.
* И только потом выпускать сервис A, который начинает это поле отправлять.
Такой баг делает релиз невозможным, так как его появление в продакшене приводит к немедленной деградации сервиса, требует остановки бизнес-процессов и сложных аварийных работ. Он ярко демонстрирует важность интеграционного и контрактного тестирования, а также соблюдения принципов совместимости API в распределённых системах.