Обеспечение обратной совместимости gRPC API с помощью protolock в GitHub Actions
В этом посте я поделюсь с вами подробной инструкцией по настройке автоматической проверки обратной совместимости gRPC API с помощью protolock в GitHub Actions.
Введение
Этот текст является продолжением первой части поста. Здесь же я хочу поделиться опытом настройки и применения protolock в GitHub Actions. Хочу начать с обсуждения того, насколько важно обеспечивать обратную совместимость при разработке API.
В процессе разработки программного обеспечения важно не только создавать качественный код, но и поддерживать его стабильность на протяжении всего жизненного цикла проекта. Особенно это касается реализации API, где критически важна обратная совместимость. При работе с gRPC API, при внесении изменений в .proto файлы есть риск нарушения совместимости с уже существующими клиентами и сервисами. Это может привести к сбоям в работе системы. Для предотвращения подобных проблем при изменении кода нужно контролировать обратную совместимость — так риски будут минимизированы.
Protolock обеспечивает проверку обратной совместимости в .proto файлах, позволяя «заморозить» текущее состояние данных, предупреждая о внесении изменений, которые могут эту совместимость нарушить. Интеграция с GitHub Actions позволяет автоматизировать выполнение проверок при каждом коммите или создании pull request, тем самым обеспечивая непрерывный контроль за совместимостью кода.
Приступим к настройке и использованию protolock и protolint в GitHub Actions.
Настройка protolock
Protolock довольно прост в использовании и имеет три основные команды:
init анализирует все .proto файлы в указанной директории и поддиректориях и создает proto.lock файл в текущей директории. Этот файл содержит снимок состояния всех .proto файлов, включая их структуру, имена полей, типы и другие атрибуты.
status анализирует все .proto файлы в указанной директории/поддиректориях и сравнивает с состоянием, сохраненным в proto.lock файле. Если все изменения обратно совместимы, команда успешно завершает выполнение. В случае нарушения обратной совместимости команда завершится с ошибкой и выведет сообщения об ошибках с указанием, какие правила в каких файлах были нарушены.
commit анализирует все .proto файлы в указанной директории и поддиректориях. Команда обновляет proto.lock файл, если изменения обратно совместимы. В противном случае proto.lock файл не будет обновлен и будут выведены сообщения об ошибках с указанием, какие правила в каких файлах были нарушены.
На сайте protolock можно наглядно увидеть, как это работает (на момент написания поста). На главной странице приведён пример .proto файла. Если для представленного .proto файла выполнить команду init, нажав соответствующую кнопку, то можно увидеть, какой proto.lock файл будет сгенерирован. Также можно попробовать внести обратно несовместимое изменение в .proto файл и, выполнив команду status, получить пример ошибок с описанием.
Теперь, зная, какие команды protolock можно использовать, настроим его работу в GitHub Actions. Создадим файл protolock_check.yml в папке .github/workflows со следующим содержимым:
name: Protolock Check & Update
on:
push:
paths:
- '**.proto'
jobs:
check:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Download protolock
run: |
wget https://github.com/nilslice/protolock/releases/download/v0.16.0/protolock.20220302T184110Z.linux-amd64.tgz
tar -zxvf protolock.20220302T184110Z.linux-amd64.tgz
- name: Initialize protolock if needed
run: |
if [ ! -f proto.lock ]; then
./protolock init --protoroot=./bankdemo
fi
- name: Run protolock status
run: ./protolock status --protoroot=./bankdemo
- name: Update proto.lock file
run: ./protolock commit --protoroot=./bankdemo
- name: Commit changes
uses: EndBug/add-and-commit@v9
with:
author_name: GitHub Action
author_email: action@github.com
message: 'Update proto.lock file'
add: proto.lock
Разберем содержимое этого файла:
Триггер on push: в данном случае workflow запускается при каждом push в репозиторий, но только если были изменены файлы с расширением proto.
Actions/checkout@v4: клонирование кода репозитория.
Download protolock: загрузка и распаковка архива с protolock.
Initialize protolock if needed: создание proto.lock файла с помощью команды protolock init, если он не был обнаружен.
Run protolock status: выполняется команда protolock status. Если команда завершилась с ошибкой, последующие шаги не будут выполнены.
Update proto.lock file: выполняется команда protolock commit и происходит обновление proto.lock файла.
Commit Changes: используя action EndBug/add-and-commit@v9, изменения в файле proto.lock коммитятся в репозиторий. Автор коммита устанавливается как «GitHub Action».
Представленный workflow обеспечивает автоматическую проверку .proto файлов на обратную совместимость и обновление файла блокировки.
Тест protolock
Для теста я создал pull request с изменениями, нарушающими обратную совместимость. Для этого в message Address я заменил поле flat на поле postal_code. Ожидаемо, что проверка protolock завершилась с ошибкой.
Пример изменений, нарушающих обратную совместимость
Workflow Protolock Check & Update завершился с ошибкой
Команда protolock status с описанием ошибок
На практике это означает что, если мы внесем данное изменение и выпустим новую версию API, забыв обновить её в одном из сервисов, то получим непредвиденные ошибки. Данный сервис, ожидая получить данные flat, будет вместо этого получать данные postal_code.
Сохраняем обратную совместимость
Как поступить, если вам необходимо внести изменения, нарушающие обратную совместимость в gRPC API? Для обеспечения плавного перехода существующих пользователей рекомендуется создать новую версию API, разместив её в отдельной директории v2 и обновить мажорную версию. Параллельно можно отметить устаревшие RPC-вызовы в версии v1 как deprecated. Такой подход позволит поддерживать обе версии сервиса параллельно, сохраняя обратную совместимость для клиентов старой версии и одновременно информируя их о необходимости перехода на более новую версию.
Чтобы сохранить обратную совместимость и проверка protolock status прошла успешно, я не стал удалять поле flat. Вместо этого под полем flat я добавил поле postal_code. После фикса проверки прошли успешно и был создан новый коммит, который обновил файл proto.lock.
Фикс обратно несовместимых изменений
После фикса проверки прошли успешно и был обновлен proto.lock файл
Заключение
В примерах я рассмотрел, как protolock защищает от изменений, нарушающих обратную совместимость gRPC API. Protolock можно эффективно использовать, запуская его локально вручную, но интеграция через GitHub Actions позволяет автоматизировать и упростить процесс проверки кода на обратную совместимость.