Обновить
8K+
3
Sergeyev Sergey@SergeyevSergey

Пользователь

11
Рейтинг
1
Подписчики
Отправить сообщение

Вариант с FastStream и брокером сообщений я на своем личном примере реализовывал тогда, когда мне нужно было подготовить систему к постепенному и частичному разносу на микросервисы. Потому что если вы вынесите только один или несколько модулей, но не все сразу, то вы больше не сможете вызывать их хендлеры внутри памяти как это было с message bus (шина сообщений). Вам придется подключать брокер. Вы конечно, по своему желанию, можете оставить одновременно и брокер и шину, но я предпочел сделать все единообразно.

А Outbox нужен для решения проблемы с атомарностью операций в eda:
Представьте что вы выполняете какую либо операцию по изменению данных внутри одной транзакции. Эта операция вызывает побочные эффекты в других частях системы, поэтому вы генерируете и отправляете событие (в брокер или шину - не важно).

Если вы отправляете событие после завершения транзакции, то у вас может упасть приложение, или произойдет сбой сети. Изменение данных произойдет, а событие не отправиться.

Если вы отправляете событие во время транзакции, то может получиться так что у вас либо событие не отправится (сбой сети, брокер не доступен, какая-то внутренняя ошибка), из-за этого откатятся все изменения, либо после отправки событий у вас произойдет ошибка, транзакция откатится, данные не сохранятся а событие уже отправлено.

В паттерне Outbox вы не отправляете событие напрямую, а сохраняете его в хранилище вместе с основными данными внутри одной транзакции. Потом poller дергает данные из таблицы Outbox раз в какое-то время и рассылает события в брокер, либо обрабатывает сам. Вы можете настроить в нем retry политику, fallback и т.д. Короче говоря - таким образом в EDA системах сохраняется атомарность.

В своей реализации я запускаю FastStream в качестве потребителя событий из брокера отдельным процессом. При этом кодовая база остается одной и той же. Меняется только точка входа в приложение. То есть у вас получается монолит только процесса обработки два - один для веб запросов, другой для потребителя ивентов. Можете назвать это "монорепо" если монолит режет слух из за нескольких запущенных процессов, главная суть в том что кодовая база остается единой. Если вы пишете синхронное Python приложение то FastStream поддерживает синхронную обработку сообщений. Если мне не изменяет память то процесс обработки там происходит почти так как вы описали, только потоки создаются на вызов а не хендлер, и складываются в общий пул после обработки, откуда потом берутся и переиспользуются для следующих запросов.

При этом если использовать паттерн Outbox вы должны запустить цикл поллера который будет дергать сохраненные события из бд и пересылать в брокер. Можно запускать его отдельным процессом, а можно и потоком внутри одного из процессов приложения, тут уж сами решайте.

В этой статье речь не о производительности, а о структурировании приложения. Ну и да, конечно, не один монолит не сравнится с микросервисами в долгосрочной перспективе, при росте нагрузки вам все равно придется разносить ваш монолит на отдельные сервисы каким бы он не был. Модульность, которую я описал в статье позволяет как раз таки заложить фундамент под этот будущий вынос.

То как реализовать dependency-injection сильно зависит от используемого веб фреймворка и от требований самого проекта. Поэтому подробно здесь не расписывал, как именно это нужно делать, но дал наводки на то, как можно, в зависимости от архитектуры.

Информация

В рейтинге
769-й
Зарегистрирован
Активность

Специализация

Бэкенд разработчик
Python