Skip to content

selyukovn/example

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

36 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Example


Общая структура

  • admin -- приложение-админка.

    • auth -- сервис авторизации.
    • cfm -- сервис отправки OTP-кодов подтверждений.
    • front -- см. admin/front/README.md.
    • gateway -- api-шлюз для BE, точка входа.
  • infrastructure -- инфраструктурные элементы, вынесенные отдельно для упрощения.

  • monitoring -- приложение для мониторинга системы.

  • node -- обвязки физического сервера, на котором развернут проект. При физическом разделении компонентов эти обвязки были бы частью каждого отдельно развернутого компонента.

Схема:


Структура компонента

Структура компонента нижнего уровня:

|- app          -- код приложения, конфиги, ресурсы, ...
|- build        -- элементы сборки контейнеров (Dockerfile'ы, конфиги, ...).
|- state        -- состояние развернутого приложения, сохраняемое между запусками (логи, данные, ...).

app

Структура основана на Hexagonal Architecture.

Для некоторых компонентов (например, front, gateway, ... ) такая организация может быть излишней -- однако, применяется намеренно однообразия ради. Спорный момент...

Используемые слои:

  • cmd / api -- клиенты ядра приложения (например, http-сервер, планировщик, ...), primary-adapter`ы. Каждый клиент обращается к ядру через Контейнер -- набор компонентов и операций, используемых этим клиентом ядра. Если разница в наборах незначительна, контейнер может быть общим для нескольких клиентов.

  • adapt -- не является полноценным слоем, содержит secondary-adapter`ы. Выделен из классического слоя инфраструктуры для наглядности.

  • opera -- классический операционный слой.

  • domain -- классический доменный слой.

  • data -- альтернатива комбинации opera и domain для случаев, ориентированных на прямую работу с данными.

  • infra -- классические инфраструктурные элементы, за исключением secondary-adapter`ов.

  • std -- утилитарный код, который можно рассматривать в рамках проекта как часть стандартной библиотеки языка. Например, тип данных Email, функции работы с массивами, ...

  • env -- "мнимый" слой окружения.

Направление зависимостей -- строго сверху вниз: вышележащий слой имеет доступ только к примыкающим снизу слоям (см. схему).

Исключением является std и использование неизменяемых объектов из всех нижележащих слоев в качестве DTO для уменьшения количества трансформаций.

Доступ к смежным слоям выполняется через интерфейсы и адаптеры.

В зависимости от приложения те или иные слои могут отсутствовать.

client не входит в приложение, но изображен на схеме для наглядности.

build

TODO

state

TODO


Запуск

  1. Копировать .env.example в .env, переопределить переменные при необходимости.

  2. Выполнить

    . tools.sh up
    

Заметки

Docker-compose и .env

Файлы не распределены по папкам компонентов (для пущей инкапсуляции), поскольку могут использовать общие элементы (например, DEPLOY_... переменные окружения). Также такой подход усложнил бы использование переменных окружения и запуск проекта (например, при конфликте переменных API_KEY в файлах /cmp1/.env и /cmp2/.env).

Сборщики логов и ротация.

Для экспорта логов в систему мониторинга используются grafana-alloy-контейнеры. Для ротации логов на сервере используется logrotate.

При текущей конфигурации (alloy-экспортеры c интервалами сбора 5s и logrotate в режиме copy-truncate) возможна ситуация, когда между сборами логов alloy-экспортером произойдет запись новых логов и ротация файла. Тогда логи, записанные в промежуток между последним сбором и ротацией, не будут собраны, поскольку уже "архивированы".

Кроме того, logrotate с copy-truncate сам по себе может терять логи во время выполнения (см. в конфиге logrotate).

Включение "архивных" файлов в сбор и tail_from_end=false подберет пропущенные, но и продублирует все ранее собранные логи, поскольку новый файл -- новый поток (как минимум метка "имя файла" изменится).

Простое и однозначное решение не было найдено, но вероятность промаха мала -- оставлено нерешенным.

.proto-файлы

Генерация кода из proto-файлов настроена на пакет с именем pb -- для api/grpc/pb. Поэтому в infra/clients/{service} пакет pb используется для удобства обновления клиента простым копированием файлов. Выделять подобный код в общие пакеты в данном проекте излишне.

Сервис может содержать grpc-сервер и несколько grpc-клиентов для других сервисов. Имена файлов, из которых сгенерен был grpc-код сервера и всех клиентов должны отличаться в пределах сервиса, иначе возникнет ошибка panic: proto: file ".proto" is already registered. Это значит, что, например, нельзя использовать файл с именем ".proto" для генерации сервера в сервисе auth и использовать для реализации клиента скопированные файлы из сервиса cfm, которые также были сгенерированы по файлу с именем ".proto" -- нужно использовать "auth.proto" и "cfm.proto".

Node Metrics Exporter

См. node/build/prometheus-exporter/README.md.

OpenApi

Используется по аналогии с protobuf/grpc для стандартизации и удобства использования структур запросов/ответов.

Разделение по бандлам

В gateway ендпоинты разделены по бандлам для простоты восприятия. Каждый бандл, если в нем используется openapi, содержит свою спецификацию -- это накладывает некоторые ограничения:

  • необходимо дублировать общие компоненты, которые требуются спецификациям нескольких бандлов:

    • папку common с общими элементами
    • components.securitySchemes из-за ограничений протокола и генератора (allOf и $ref).
  • необходимо прописывать полный путь в урле внутри бандла, хотя напрашивается использование относительного. Технически это можно было бы сделать в точке инициализации роутера, передав префикс в BaseUrl-опции, однако в получаемой документации этот префикс не будет добавлен, что будет сбивать с толку.

Коды ответов

В спецификациях сокращено количество описываемых HTTP‑статусов до трёх базовых сценариев:

  • 200 -- успешный ответ;
  • 422 -- ожидаемые неуспешные сценарии (бизнес‑ошибки) с уточняющим полем code и текстовым сообщением message.
  • редиректы (например, 307 Temporary Redirect).

Все прочие HTTP-коды в спецификации не описываются: они считаются внештатными ситуациями, багами и т.д.

Такой подход выбран для упрощения как спецификации, так и использования сгенерированного кода, поскольку генератор создает отдельный тип (структуру) респонса для каждого описанного в спецификации кода ответа.


About

Учебно-демонстрационный проект. В процессе разработки...

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors