Единое место хранения всех .proto-файлов, используемых нашими приложениями. Совокупность всех .proto-файлов называется протоколом определенной версии.
Другие приложения должны получать .proto-файлы именно из репозитория, а не хранить их самостоятельно.
Имя директории - это имя сервиса в нашей архитектуре и обычно должно совпадать с именем репозитория данного сервиса. Однако, конечное приложение, использующее протокол, может реализовывать API одновременно нескольких сервисов.
Сущности service должны определяться в файле с именем api.proto. Имена этих сущностей должны иметь формат <ИмяВебСервиса>Api. Данный суффикс позволяет устранить возможный конфликт одинаковых названий service и message.
Сущности message могут определяться как в api.proto, так и entities.proto - это зависит от типа и назначения сущностей. В файле api.proto могут объявляться только те message, которые необходимы лишь для описания входящих и исходящих сообщений для определенных в нём service. В файле entities.proto должны определяться сущности, являющиеся понятиями предметной области, которыми оперирует конечный сервис, даже если такие сущности используются в качестве входящих/исходящих для service.
Сущности message и enum, не подходящие сами по себе под описанные выше критерии, но используемые другими сущностями message, должны определяться в том файле, в котором находятся использующие их сущности. А если таковые есть и в api.proto, и в entities.proto, то - в entities.proto.
Недопустимо импортировать файлы api.proto в файлы entities.proto. Следовательно, если какая-то сущность message использует сущность из файла api.proto, последняя должна быть перенесена в entities.proto.
Имена message, service и прочих сущностей должны быть уникальными среди всех .proto-файлов в любых директориях репозитория. Это обусловлено тем, что генератор кода grpc_tools.protoc будет ругаться на конфликт имён, если при импорте сущностей в .proto-файле появятся дубликаты.
- Порядок импорта файлов:
- Находящиеся в библиотеках, например,
google/protobuf/empty.proto - Находящиеся в локальной директории сервиса, например,
entities.proto - Находящиеся в других директориях проекта, например,
common.proto - В оставшихся случаях порядок определяется сортировкой по алфавиту без учёта регистра букв
- Находящиеся в библиотеках, например,
- Для пустых сообщений использовать тип
google.protobuf.Empty - Для полей со временем использовать тип
google.protobuf.Timestamp - Для полей с денежными суммами использовать тип
string
Действия в данном репозитории:
- Проектирование и согласование изменений
- Внесение изменений в
.proto-файлы через новую ветку - Приёмка пул реквеста, прохождение автоматических проверок, слияние ветки с master
- Указание новой версии протокола с помощью tag репозитория (обычно на merge-коммит ветки master) в формате "v<порядковый номер>"
В качестве порядкового номера используется либо ручной счётчик, либо номер билда из TeamCity.
Действия в приложении, использующем протокол:
- Выбор необходимой для приложения версии протокола
- Скачивание
.proto-файлов данной версии - Генерация программных файлов клиента/сервера в момент сборки образа приложения
Данные инструкции скачивают .proto-файлы конкретной версии из репозитория protos (см. процесс выпуска новой версии протокола):
FROM alpine/git:1.0.7 AS protos-gitter
ARG PROTOS_DSN=https://github.com/galtsos/protos.git
ARG PROTOS_BRANCH
RUN set -e; \
# Unfortunately there is a glitch when store result in the default /git directory
mkdir /protos; \
cd /protos; \
git clone --depth 1 -b $PROTOS_BRANCH -- $PROTOS_DSN .; \
rm -rf .gitЧтобы скачать необходимую версию протокола (тег/ветку репозитория), нужно указать её в значении аргумента сборки PROTOS_BRANCH либо прямо в указанных выше инструкциях (предпочтительно), либо в docker build в аргументе --build-arg.
Далее нужно разместить инструкции для сборки целевого образа; например, Python-приложения:
FROM python:3.7
RUN pip install pipenv
WORKDIR /var/app/src
COPY src/Pipfile* ./
RUN pipenv install --deploy --system
COPY src/ .
COPY --from=protos-gitter /protos protos_orig/protos
# Just for inject a different proto-files for development
#COPY protos protos_orig/protos
RUN set -e; \
cd protos_orig; \
python -m grpc_tools.protoc -I. --python_out=.. protos/common.proto; \
cp protos/common.proto ../protos/common.proto ; \
SERVICES="deal exchange-trading"; \
for service in $SERVICES; do \
python -m grpc_tools.protoc -I. --python_out=.. \
protos/$service/api.proto protos/$service/entities.proto; \
python -m grpc_tools.protoc -I. --grpc_python_out=.. protos/$service/api.proto; \
dir_name=$(echo $service | sed 's/-/_/g'); \
cp protos/$service/*.proto ../protos/$dir_name ; \
done; \
rm -rf ../protos_origЧтобы последнее заработало, нужно добавить пакет grpcio-tools в Pipfile. Также нужно не забыть отредактировать список SERVICES в соответствии с нужными сервисами и в обоих наборах инструкций указать LABEL maintainer="...".
В результате выполнения этих наборов инструкций в директории /var/app/src/protos будут находиться поддиректории с именами сервисов, например exchange_trading, в которых будут находиться pb2- и .proto-файлы:
/var/app/src/protos# ls -R
.:
common_pb2.py common.proto deal exchange_trading
./deal:
api.proto api_pb2.py api_pb2_grpc.py entities.proto entities_pb2.py
./exchange_trading:
api.proto api_pb2.py api_pb2_grpc.py entities.proto entities_pb2.py
При разработке приложения может быть удобно получить сгенерированные файлы клиента и сервера из образа на локальный диск разработчика. Воспользуйтесь командами:
cd $LOCAL_SERVICE_DIR/src/
docker run -d --rm $IMAGE bash -c 'sleep 10' | xargs -i{} docker cp {}:/var/app/src/protos - | tar -xДобавьте эти строчки в .gitignore, чтобы случайно не закоммитить лишние файлы в репозиторий приложения:
protosВ указанных выше инструкциях сборки образа есть комментарий, как использовать локальные .proto-файлы вместо хранящихся в репозитории protos.
Если при разработке приложения требуется внести изменения в репозиторий с .proto-файлами, то процесс должен быть следующим:
- В репозитории
protosсоздаётся новая ветка с желаемыми изменениями - В аргументе сборки
PROTOS_BRANCH(репозиторий приложения) указывается имя данной ветки - Изменения протокола проверяются на пригодность для приложения
- Ветка в репозитории
protosпроходит согласование по процессу выпуска новой версии протокола - После этого в аргументе сборки
PROTOS_BRANCHуказывается новая версия протокола