简体中文 English 繁體中文 日本語 Русский
本文为静态镜像,内容以交互版为准 在交互式文档中心打开 →

Ящик для диалогов (Транскрипт)

Ящик для диалогов автоматически записывает сообщения, отправленные и полученные роботом (организованные по ключу сессии platform:detail_type:target_id), и предоставляет исторические данные для восстановления диалога (event.history), сравнения изменений в теневом модуле, воспроизведения при холодном запуске и т.д. В настоящем документе описаны модель хранения, что защищает каждый регулятор стратегии сохранения, а также реальная стоимость разрешения API и снятия ограничений во время выполнения.

Прочтите раздел «Риски и аудит» перед изменением ограничений — у каждого регулятора есть свои причины существования.

Как это работает

Сообщение ──append()──▶ Буфер записи (в памяти deque, жёсткий лимит 4096 строк)
                        │  Батчевая запись на диск каждые 1 секунду (один батч ≤64 строк, одна транзакция)
                        ▼
              Таблица transcript в бэкенде storage (по умолчанию sqlite)
                        │  Приблизительно каждые 32 строки запускается ленивая очистка хранения
                        ▼
              ┌─ FIFO-обрезка по сессиям (max_per_session, по умолчанию 50 строк)
              └─ Глобальное удаление по TTL (ttl_hours, по умолчанию 168 = 7 дней)

Три уровня защиты, каждый защищает от разных рисков:

Параметр Значение по умолчанию Что защищает Последствия отключения (=0)
Лимит буфера записи 4096 строк (константа, не настраивается) Память: накопление сообщений при недоступности хранилища не приведёт к переполнению RAM Невозможно отключить — это защита памяти
Обрезка текста 2000 символов (константа, не настраивается) Использование памяти и диска на одну строку Невозможно отключить
max_per_session 50 строк/сессия Рост диска: бесконечное накопление истории в одной сессии История сессии будет бесконечно расти
ttl_hours 168 (7 дней) Рост диска: долгосрочное накопление истории по всем сессиям Таблица transcript будет бесконечно расти

Важное понимание: буфер записи имеет жёсткий лимит, поэтому отключение политик хранения не приведёт к превышению памяти;
Реальные риски связаны с уровнем хранения и потребителями данных (см. следующий раздел).

Конфигурация

[ErisPulse.transcript]
enabled = true          # Автоматическая запись включена
max_per_session = 50    # Количество записей в сессии (0 = отключить обрезку сессии)
ttl_hours = 168.0       # Общая продолжительность хранения (в часах, 0 = никогда не удалять)

Переменные среды также применяются: ERISPULSE_TRANSCRIPT_MAX_PER_SESSION, ERISPULSE_TRANSCRIPT_TTL_HOURS. Изменения конфигурации применяются в режиме горячего перезагрузки (в пределах частоты записи в буфер, задержка до ~1 секунды).

API для переопределения во время выполнения

Для динамического изменения (например, временного увеличения срока хранения для определённой сессии):

from ErisPulse import transcript

# Переопределение (приоритет над конфигурацией; только в памяти, после перезапуска восстанавливается значение из конфигурации)
transcript.set_retention(max_per_session=500, ttl_hours=24 * 30)

# Получение текущих значений и источника
transcript.get_retention()
# {'max_per_session': 500, 'ttl_hours': 720.0, 'overridden': ['max_per_session', 'ttl_hours']}

# Восстановление значений из конфигурации
transcript.reset_retention()

Риски и аудит: что нужно знать перед отключением ограничений

После отключения max_per_session / ttl_hours (или при значительном увеличении их значений) таблица transcript будет расти бесконечно вместе с количеством сообщений. Это приведёт к следующим последствиям:

  1. Заполнение диска — SQLite-файл будет постоянно увеличиваться, и при заполнении диска слой хранения фреймворка станет недоступен;
  2. Ухудшение производительности запросов — стоимость сканирования в get() / recent() / get_by_trace() будет расти вместе с ростом таблицы;
  3. Давление на память (истинный источник OOM) — потребители, загружающие историю целиком в память (восстановление диалога с историей, панель с полной выгрузкой, ваш бизнес-код get(session, n) с большим n), будут потреблять всё больше памяти, что в экстремальных случаях приведёт к OOM kill.

Перед отключением задайте себе три вопроса: как долго вам нужна история? Какого размера? Кто будет её очищать?
Если ответ зависит от "никогда не удалять", правильным решением обычно является внешняя архивация (периодическая отправка старых данных в специальную базу), а не бесконечное хранение в почтовом ящике.

Средства аудита (регулярная проверка размера таблицы):

# С помощью ORM/SQL-конструктора проверьте количество строк и объём (пример для sqlite)
from ErisPulse import storage

row = storage.Table("transcript").raw_sql("SELECT COUNT(*) AS n FROM transcript")
-- Прямой запрос к файлу sqlite (объём таблицы)
SELECT COUNT(*) FROM transcript;

В логах появится предупреждение стратегия хранения была отключена — это означает, что кто-то отключил стратегию, установив значение 0. Убедитесь, что это ваше действие.

Границы с другими механизмами