PostChatMailTaskRunner

src/chathouse/components/tasks/post-chat-mail-task.runner.ts

Observer на [[services/chathouse/services/operator-runner]]. Після чат-переписки з RU — якщо TU ще не написала mail додатково — створює mail-таск для оператора.


Таймери

МоментЗатримкаУмова
Перша перевірка після старту OperatorRunner10 сек≤ 10 анкет у оператора
Перша перевірка після старту OperatorRunner30 сек> 10 анкет (розподіл навантаження)
Кожна наступна перевірка60 сек після попередньоїЗавжди, незалежно від результату

Таймер рекурсивний (setTimeout): наступний запуск планується після завершення поточного calculate().

Додаткова затримка всередині циклу: статистика враховується тільки якщо від події минуло більше 10 хвилин (POST_CHAT_MAIL_MS). Свіжіші події — ігноруються.


Обмеження

  • Немає глобального ліміту тасків на оператора — але таск не створюється якщо по парі TU+RU вже є активний UnansweredMailTask, UnansweredMessageTask або NeedToWriteMailTask.
  • Тільки діалоги з доступними mail-лімітами (favoriteDialogsWithMailLimits). Якщо ліміти вичерпані — діалог кешується в Redis на 10 хв і пропускається.
  • Тільки платна активність RU (isFree: false). Безкоштовні дії не враховуються.
  • Якщо TU вже надіслала mail після останнього RU-повідомлення в чаті — таск не створюється, стат додається в closedTasks.

Ініціалізація при старті

  1. Будуються lookup-мапи між DB ID, API ID і ULID кожної TU оператора.
  2. З БД завантажуються вже оброблені таски за останні 2 місяці → заповнюється closedTasks (Set рядкових ключів).
  3. Перша перевірка запускається із затримкою (див. таблицю вище).

Цикл перевірки (кожні 60 сек)

  1. Отримання діалогів. З OperatorRunner отримуються активні favorite-діалоги з mail-лімітами (getAllFavoriteMailDialogs).

  2. Свіжа статистика. З тимчасової таблиці завантажуються записи чат-активності RU (sum > 0, isFree: false, тільки для manUlid-ів з цих діалогів, тільки для TU оператора).

    Типи активності що відстежуються: text_message_send, photo_message_send, video_message_send, audio_message_send, sticker_message_send, send_gift, present_send, watch_private_video, profile_erotic_photo, profile_private_photo, profile_private_library_video, profile_private_library_photo.

  3. Дедуплікація. Для кожної пари TU+RU залишається тільки найновіший запис.

  4. Перевірка надісланих mail. Завантажуються сьогоднішні inmail-відправки оператора. Якщо TU вже надіслала mail після дати статистики — стат додається в closedTasks (відповідь вже є).

  5. Фільтрація по closedTasks. Кожен стат-запис перетворюється на ключ ladyDbId_manUlid_dateWithTime. Вже закриті — пропускаються.

  6. Створення тасків. Записи групуються по ladyDbId. Для кожного стату в рамках TU:

    • Знаходиться діалог по парі TU+RU.
    • Якщо від події минуло менше 10 хвилин → пропустити.
    • Якщо є активний UnansweredMailTask, UnansweredMessageTask або NeedToWriteMailTask по цій парі → пропустити.
    • Якщо діалог позначений як “forgotten” в Redis → пропустити (ліміти кешовані).
    • API-запит: отримати повідомлення діалогу, перевірити чи є доступні mail-ліміти. Якщо ні — закешувати в Redis на 10 хв, пропустити.
    • Створити таск типу NeedToWriteMailTask з модулем postChatMail через TaskFactory.
    • Зберегти в БД і додати до стору оператора.

Кеш оброблених подій (closedTasks)

In-memory Set. Дві схеми ключів:

КлючКоли додається
ladyDbId_manUlid_eventTriggerTaskКоли таск закрито оператором (pushToCacheTaskAnswered)
ladyDbId_manUlid_dateWithTimeПісля створення таску або виявлення що TU вже відповіла (pushToCacheStatistics)

При старті відновлюється з БД (таски за 2 місяці). Redis-кеш для “без лімітів” (checkPostChatMailDialog) — окремий, не входить в closedTasks.