Skip to content

Аудит архитектуры: связи подсистем, проблемы, рекомендации #480

@shikhalev

Description

@shikhalev

Контекст

Анализ текущих связей между подсистемами AI Secretary System. Цель — зафиксировать как подсистемы взаимодействуют, где проблемы, и как должно быть правильно.


1. Карта подсистем

                    ┌─────────────────────────────────────────────┐
                    │         orchestrator.py (~4100 строк)        │
                    │  God Object: startup, DI, ~100 legacy API,  │
                    │  widget endpoints, background tasks          │
                    ├──────────────┬───────────────┬──────────────┤
                    │              │               │              │
              ┌─────┴─────┐  ┌────┴────┐   ┌──────┴──────┐  ┌───┴───┐
              │ 26 Routers │  │ Service │   │ DB Layer    │  │ Caches│
              │ app/       │  │ Layer   │   │ db/         │  │       │
              │ routers/   │  │ (split) │   │             │  │       │
              └─────┬──────┘  └────┬────┘   └──────┬──────┘  └───┬───┘
                    │              │               │              │
        ┌───────────┼──────────────┼───────────────┤              │
        │           │              │               │              │
   ┌────┴───┐ ┌────┴───┐   ┌─────┴──────┐  ┌────┴─────┐  ┌────┴────┐
   │TG Bot  │ │WA Bot  │   │Root svc:   │  │db/integr.│  │In-memory│
   │subproc │ │subproc │   │cloud_llm,  │  │30+ mgr   │  │5 кешей  │
   │(HTTP→  │ │(HTTP→  │   │voice,stt   │  │singletons│  │+ Redis  │
   │ orch)  │ │ orch)  │   ├────────────┤  └──────────┘  └─────────┘
   └────────┘ └────────┘   │app/svc:    │
                            │amocrm,rag, │
        ┌────────┐          │sales,woo   │
        │Widget  │          └────────────┘
        │(public │
        │HTTP)   │     ┌────────────┐
        └────────┘     │Claude      │
                       │Bridge      │
        ┌────────┐     │(subprocess)│
        │Admin   │     └────────────┘
        │Panel   │
        │(JWT)   │
        └────────┘

Механизмы связи

Связь Механизм Файлы
Orchestrator → DB Импорт синглтонов из db/integration.py + прямой AsyncSessionLocal orchestrator.py:85-99, 3704, 3752, 3994
Routers → DB Смесь: одни через менеджеры, другие через прямой AsyncSessionLocal chat.py:18 vs audit.py:13
Routers → Services ServiceContainer через get_container() или Depends() app/dependencies.py
Routers → Bot managers Прямой импорт глобальных синглтонов from multi_bot_manager import multi_bot_manager
TG/WA Bot → Orchestrator HTTP API через LLMRouter (httpx + BOT_INTERNAL_TOKEN JWT) telegram_bot/services/llm_router.py
Bot → Config Env vars + JSON в /tmp + HTTP fallback multi_bot_manager.py:111-150
Widget → Orchestrator Public HTTP endpoints (без auth) в orchestrator.py orchestrator.py:3648-4040
Admin Panel → Orchestrator JWT auth, HTTP REST + SSE admin/src/api/*.ts
Bridge → Orchestrator Subprocess, OpenAI-compatible API bridge_manager.py

Data flow

TELEGRAM/WHATSAPP           WIDGET                    ADMIN PANEL
 ↓                           ↓                          ↓
Message handler          POST /widget/session       POST /admin/chat/
 ↓                           ↓                     sessions/{id}/stream
Session store (память)   Session store (DB)              ↓
 ↓                           ↓                     Session (DB)
LLMRouter.chat_stream()  orchestrator.py widget ep       ↓
 ↓                           ↓                     chat.py streaming
POST /admin/chat/        LLM selection (дубль!)     LLM selection
sessions/{id}/stream     RAG injection              RAG injection
 ↓                           ↓                          ↓
        ───────── CloudLLMService / vLLM ─────────
                         ↓
                   SSE response

2. Выявленные проблемы

P1 — Операционные риски (влияют на uptime)

2.1. Нет мониторинга подпроцессов ботов

  • Где: multi_bot_manager.py, whatsapp_manager.py
  • Суть: Бот-подпроцесс падает — оркестратор не знает. process.poll() проверяется только при API-вызове /status, не проактивно.
  • Риск: Пользователи TG/WA получают тишину. Нет авторестарта.

2.2. Нет graceful shutdown

  • Где: orchestrator.py:1156-1161
  • Суть: При shutdown — только shutdown_database(). Боты НЕ останавливаются (start_new_session=True). Background tasks НЕ отменяются. Задачи _cleanup_expired_sessions и _periodic_vacuum запущены через create_task() без сохранения reference.
  • Риск: Orphaned процессы, дубли ботов при рестарте.

2.3. Потеря сессий ботов при крэше

  • Где: telegram_bot/services/session_store.py, whatsapp_bot/services/session_store.py
  • Суть: TG и WA боты хранят историю разговоров только в памяти. Крэш/рестарт = полная потеря контекста.
  • Нюанс: Боты уже создают сессии в оркестраторе через _ensure_session(), т.е. сообщения дублируются в DB. Но бот при рестарте не восстанавливает из DB — создаёт новые сессии.

P2 — Архитектурный долг (усложняет развитие)

2.4. God Object — orchestrator.py (4100 строк)

  • Суть: Совмещает: инициализацию сервисов, ~100 legacy эндпоинтов, widget endpoints (~300 строк), background tasks, helper functions.
  • Проблема: Widget-логика (LLM selection, RAG injection, amoCRM lead creation) дублирует chat.py.

2.5. Два паттерна доступа к БД

Через менеджеры (@retry_on_busy) Прямой AsyncSessionLocal (без retry)
chat.py, telegram.py, whatsapp.py, faq.py, llm.py, amocrm.py, wiki_rag.py, kanban.py, workspace.py, auth.py, roles.py, woocommerce.py, claude_code.py, backup.py audit.py, usage.py, bot_sales.py, legal.py, github_webhook.py + orchestrator.py (3 места)

8 точек доступа обходят менеджеры → нет retry, нет единообразной обработки ошибок.

2.6. ServiceContainer покрывает только hardware-сервисы

  • В контейнере: TTS, STT, LLM, GSM, WikiRAG.
  • Всё остальное (30+ DB-менеджеров, bot managers, bridge) — глобальные синглтоны через прямой import.
  • Результат: два механизма DI — Depends(get_llm_service) vs from db.integration import async_chat_manager.

2.7. Дублирование LLM backend selection

  • app/routers/chat.py:624-697 — для admin/bot сессий
  • orchestrator.py:3880-3892 — для widget сессий
  • Одна и та же логика: parse cloud:{provider_id}, load provider, fallback chain.

P3 — Средний приоритет

2.8. Фрагментация сервисного слоя

  • Root (12 файлов): cloud_llm, voice, stt, managers
  • app/services/ (8+ файлов): amocrm, rag, sales, woo
  • Нет документированного критерия разделения.

2.9. Инкогерентность кешей

Кеш Файл Тип Инвалидация
SessionCache (jti→user) auth_manager.py in-memory dict Ручная при revoke
PermissionsCache (role→perms) auth_manager.py in-memory dict Ручная при role update
MemberRoleCache (user,ws→role) auth_manager.py in-memory dict Ручная при role change
FAQ в CloudLLMService cloud_llm_service.py instance var При явном reload
TTS streaming orchestrator.py dict + Lock LRU
Redis (amocrm pipelines/leads) db/redis_client.py Redis TTL

Нет единой стратегии. Пропуск ручного invalidate = stale data.

2.10. Config из трёх источников

  • .envos.getenv() повсюду
  • DB (config table, provider configs, bot configs)
  • Subprocess env (snapshot at spawn time, не обновляется)

2.11. Отдельные sales DB в подпроцессах

  • telegram_bot/sales/database.pydata/sales.db
  • whatsapp_bot/sales/database.pydata/wa_sales_{id}.db
  • Вне основной DB, нет единого view на воронку.

3. Как должно быть правильно (рекомендации)

Tier 1 — Критичные (uptime)

# Рекомендация Объём Суть
R1 Health monitor подпроцессов S (~50 строк) Background task: poll process.poll() каждые 30с. Если dead + auto_start=True → рестарт. Логирование.
R2 Graceful shutdown S (~30 строк) В shutdown_event(): stop all bots → stop bridge → cancel tasks → close DB. Сохранять Task references.
R3 Bot sessions из DB L (рефакторинг) Бот при рестарте восстанавливает сессии из orchestrator API. Убрать дублирование in-memory ↔ DB.

Tier 2 — Высокий (архитектура)

# Рекомендация Объём Суть
R4 Widget → app/routers/widget.py M (move) Вынести ~300 строк widget endpoints из orchestrator.py. Заодно переиспользовать LLM selection из chat.py.
R5 Консолидировать DB-доступ M 5 роутеров (audit, usage, bot_sales, legal, github_webhook) + orchestrator.py → через менеджеры. Все получат @retry_on_busy.
R6 Shared LLM resolution S (~50 строк) Extract resolve_llm_backend() → использовать в chat.py и widget router.

Tier 3 — Средний

# Рекомендация Объём Суть
R7 Реестр background tasks S TaskRegistry(name→Task). Cancel all in shutdown. Show in /health.
R8 Cache invalidation events M Event-based invalidation вместо ручных вызовов.
R9 Merge sales DB L Перенести sales tables в secretary.db. Унифицировать миграции.

Tier 4 — Low priority

# Рекомендация Объём
R10 Документировать правило root/ vs app/services/ Текст
R11 Hot-reload конфига ботов (без рестарта) M

4. Рекомендуемый порядок

R2 (shutdown)  ──→  R1 (health monitor)  ──→  R7 (task registry)
         независимо от:
R4 (widget router)  ──→  R6 (shared LLM resolution)
         независимо от:
R5 (DB consolidation)
         потом:
R3 (bot sessions)  ──→  R9 (sales DB merge)
  • R1+R2 — один PR, минимальный риск
  • R4+R6 — второй PR, чистый рефакторинг (move + extract)
  • R5 — третий PR, каждый роутер отдельным коммитом

S = 1-2 часа, M = полдня, L = день+

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentation

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions