Что у меня есть сейчас:
- Сервис записи в БД (валидирует входящие данные, ищет дубликаты)[FastAPI]
- Сервис конвертации и преобразования данных (забирает данные из сервиса БД и создаёт Celery таски)[FastAPI]
- Сервис с Celery на борту + к нему Redis в качестве брокера
- Сервис фронта (не я пилил, хз что там), который взаимодействует с первыми двумя апишками [NestJS]
- Собственно сам фронт [Angular]
Соответственно, как пример:
После записи данных в базу я из сервиса БД дёргаю эндпоинты сервиса конвертации, что бы инициировать конвертацию в форматы по умолчанию. Если нужен другой формат, то пользователь жмёт нужные кнопки из интерфейса, а сервис фронта уже дёргает ручки сервиса конвертации. Всё это надо логировать, в будущем понадобится сквозная трассировка и т.п. При обрастании функционалом (и следовательно, увеличении кол-ва сервисов) увеличится взаимодействие, повысится связность. Придётся обрабатывать в коде случаи отваливания части сервисов и т.п. Как я понимаю, если перейти с ручного дёрганья эндпоинтов на событийную модель взаимодействия сервисов, можно будет привести систему к следующему виду:
- Сервис записи в БД
- Сервис ручной инициации конвертации, преобразования - апишка без логики создания задач, просто эндпоинты, создающие эвенты по типу - была запрошена конвертация в такой-то формат.
- Сервис конвертации
- Сервис преобразования данных
- Сервис фронта
- Фронт
Тогда, имея
Pub/Sub шину в виде
NATS, я могу всё сделать следующим образом. Пользователь отправляет данные в сервис БД, после валидации данные пишутся в БД и в
NATS subject пушится сообщение (эвент) с информацией о новых данных. На этот эвент у нас подписаны сервисы конвертации и сервис фронта. Соответственно, в сервисе конвертации должна начаться конвертация, а у пользователя на страничке мигнуть лампочка - данные записаны, всё ок.
Сервис конвертации, при начале конвертации создаёт эвент - началось. На этот эвент подписан фронт - пользователю мигает соответствующая лампочка и дальше в том же духе. С первого взгляда всё просто, но вот при дальнейшем обдумывании у меня возникают вопросы.
При создании
REST сервисов я использую
FastAPI, для него существует настроенный
Docker образ, в котором достаточно положить приложение в определенное место и всё заверте... Упакованные в такие образы апишки способны обслуживать огромное количество пользователей. Однако, из того, что я описал выше видно, что не все сервисы -
REST API. Сервисы конвертации и преобразования данных - по факту просто скрипты вынесенные в отдельные контейнеры и я не имею понятия, как грамотно это всё организовать. Если я напишу скрипт, который просто в бесконечном цикле ожидает сообщения (эвенты) в
subject'е
NATS, то как правильно потом это всё запускать в контейнере, что бы скрипт мог обслуживать сразу n-ное количество эвентов. Нужно ли это вообще? Есть ли примеры, статьи, видео по теме? Всё что нахожу - очередные "Как запустить
Flask в докере!"
Как одно из предположений:
В сервисах конвертации и преобразования создавать всё те же
Celery таски и держать параллельно сервис с его воркерами, в которых так же пушить в
NATS эвенты с инфой о ходе процесса.