Protobuf хорошо переносит эволюцию схемы, но только если соблюдать правила совместимости. Изменение номера поля, типа, enum или смысла поля может сломать старые сервисы даже при успешной сборке.
Сначала нужно сравнить старую и новую .proto-схему: номера полей, типы, removed fields, enum values и generated code в клиентах.
Коротко: что делать
- Найти commit, где изменился .proto файл
- Сравнить field numbers и типы полей
- Проверить, не переиспользовались ли удаленные номера
- Проверить enum и default values
- Проверить, обновились ли generated clients у всех сервисов
Основные причины
У этой проблемы редко бывает одна универсальная причина. Обычно нужно проверить связку настроек, данных, кода и внешних сервисов, а потом уже выбирать способ исправления.
- Изменен номер существующего поля
- Поле удалено без reserved
- Тип поля изменен несовместимо
- Переиспользовано старое enum value
- Новый сервер ожидает поле, которого старый клиент не отправляет
Пошаговая диагностика
Диагностику лучше вести от конкретного примера: один пользователь, один запрос, один документ, одно событие или один экран. Так проще увидеть точку, где система начинает вести себя неправильно.
- Сравнить descriptor старой и новой версии
- Проверить ошибки сериализации и десериализации
- Запустить старый клиент против нового сервера на тесте
- Проверить generated code и версии пакетов
- Проверить backward/forward compatibility сценарии
Как исправить проблему
Исправление должно закрывать корневую причину, а не только внешний симптом. Если проблема связана с доступами, платежами, данными или безопасностью, сначала стоит сделать резервную копию и проверить правку на тестовом сценарии.
- Вернуть номера и типы полей, если они были изменены
- Пометить удаленные поля как reserved
- Добавлять новые поля с новыми номерами без ломки старых
- Версионировать контракт, если изменение действительно несовместимо
- Добавить contract tests между сервисами
Безопасный план решения
Сначала восстановите совместимость для старых клиентов, затем планируйте миграцию на новую версию контракта. В микросервисах нельзя считать, что все обновятся одновременно.
Чего не стоит делать
- Не переиспользовать номера удаленных полей
- Не менять смысл поля без новой версии
- Не выкатывать новый .proto без contract tests
- Не обновлять только сервер, забывая о старых клиентах
Что подготовить перед исправлением
- Старый и новый .proto файл
- Ошибка клиента или сервера
- Список сервисов и их версии
- Как происходит генерация кода
FAQ
Можно ли удалить поле из protobuf?
Можно перестать его использовать, но номер лучше оставить reserved, чтобы не сломать старые данные и клиентов.
Почему сборка проходит, а runtime ломается?
Сборка проверяет код текущей версии, а runtime сталкивается с другими версиями сервисов и контрактов.
Как избежать повторения?
Ввести правила эволюции схемы, проверки совместимости и contract tests.
Когда стоит обратиться за помощью
Помощь нужна, если gRPC-сервисы уже в production и нельзя одновременно обновить всех клиентов.
Итог
Начните со сравнения .proto и field numbers. Если нужно восстановить совместимость gRPC/protobuf и настроить contract tests, можно написать в Telegram @rabotator_support.