-
Notifications
You must be signed in to change notification settings - Fork 5
Open
Labels
P3Low priority / BacklogLow priority / Backlogphase:5-techdebtPhase 5: Technical DebtPhase 5: Technical DebtrefactoringArchitectural refactoringArchitectural refactoring
Description
Parent
Часть плана модульной декомпозиции: #489
Цель
Заменить прямые импорты и вызовы между несвязанными доменами на события через EventBus. Модули публикуют события, другие модули подписываются. Нет прямых зависимостей между доменами одного уровня.
События для реализации
Каждое событие — отдельный PR:
| Событие | Публикует | Подписчик | Что заменяет |
|---|---|---|---|
KnowledgeUpdated |
knowledge | llm (reload FAQ cache) | Прямой вызов из wiki_rag роутера |
WidgetSessionCreated |
channels/widget | crm (create amoCRM lead) | create_task(_widget_create_amocrm_lead) в orchestrator.py |
WidgetMessageSent |
channels/widget | crm (append note to lead) | Прямой вызов в widget endpoint |
WidgetContactSubmitted |
channels/widget | crm (link contact to lead) | Прямой вызов в widget endpoint |
UserRoleChanged |
core/auth | core/cache (invalidation) | Ручной cache.invalidate() |
SessionRevoked |
core/auth | core/cache (invalidation) | Ручной _session_cache.remove() |
DatasetSynced |
crm, ecommerce | knowledge (reindex collection) | Прямой вызов reindex в amocrm/woocommerce роутерах |
ConfigChanged |
core/config | affected modules (reload) | Нет (сейчас требует рестарт сервиса) |
BotProcessDied |
channels/telegram, /whatsapp | monitoring (alert), self (auto-restart) | Нет (сейчас бот падает молча) |
Паттерн
# modules/channels/widget/events.py
@dataclass
class WidgetSessionCreated(BaseEvent):
session_id: str
widget_instance_id: str
visitor_metadata: dict
# modules/channels/widget/router.py — публикация
await bus.publish(WidgetSessionCreated(
session_id=session.id,
widget_instance_id=widget_id,
visitor_metadata=metadata,
))
# modules/crm/service.py — подписка
class CRMService:
def setup_events(self, bus: EventBus):
bus.subscribe(WidgetSessionCreated, self._on_widget_session)
async def _on_widget_session(self, event: WidgetSessionCreated):
"""Создать lead в amoCRM при создании виджет-сессии."""
...Порядок работы
Начать с самых простых и изолированных событий:
UserRoleChanged,SessionRevoked— внутри core, самый безопасныйKnowledgeUpdated— простая связь knowledge → llmDatasetSynced— crm/ecommerce → knowledgeWidgetSessionCreated/MessageSent/ContactSubmitted— widget → crmBotProcessDied— channels → monitoring (новая функциональность)ConfigChanged— последним (широкий blast radius)
Критерии готовности
- Все перечисленные прямые зависимости между доменами заменены на события
- Каждый модуль определяет свои события в
events.py - Подписки регистрируются в
setup_events()при инициализации модуля - Ошибки в обработчиках логируются, не роняют publisher
- Граф зависимостей соответствует схеме из Целевая архитектура: модульная декомпозиция #481
- Все тесты проходят
- CI зелёный
Риск: низкий-средний
Каждое событие меняет ровно один поток данных. Если обработчик упал — publisher продолжает работать (fire-and-forget с логированием).
Зависимости
- Фаза 0 (EventBus должен существовать)
- Фаза 4 (EventBus должен быть интегрирован в startup — модули регистрируют подписки)
Оценка: M (5-6 PR, по одному событию)
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
P3Low priority / BacklogLow priority / Backlogphase:5-techdebtPhase 5: Technical DebtPhase 5: Technical DebtrefactoringArchitectural refactoringArchitectural refactoring