Единое место хранения всех .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
указывается новая версия протокола