Follow-up Mail сервіс
Окремий per-TU сервіс для всіх причин створення FollowUpMail. Зводить їх в одну перевірку пари TU+RU і передає готовий кандидат у Task Factory. Активні таски не тримає.
Маркери
У фавориті зберігається:
followUpMail: {
postChatSourceTaskId?
postChatDueAt?
lastBurstSourceTaskId?
lastReadEventKey?
}postChat*— таймер після останнього закритогоUnansweredMessage;lastBurstSourceTaskId— останнє закриття Unanswered, для якого вже виконана 50% спроба;lastReadEventKey— остання оброблена статистична подія прочитання листа.
Ініціалізація
Task history і favorite.followUpMail відновлюють post-chat таймери та вже оброблені burst/read-події. Прострочений post-chat таймер перевіряється одразу; повторно рандомити lastBurstSourceTaskId або обробляти lastReadEventKey не можна. Умова «останній лист TU старший за 6 годин» стану не має й перевіряється з наступного RU Online snapshot.
Джерела
Останній лист TU старший за 6 годин
RU Online передає active favorites online. Пара не перевіряється, якщо вже має активний mail-таск або очікує перевірки з іншого mail-джерела. Сервіс читає mail history і передає кандидат, якщо останній лист від TU старший за 6 год.
Лист TU прочитано RU
Джерело — статистика Golden EmailRead/OpenAttach* або Chathouse inmail_read*.
Подія є новою, якщо:
- її ключ не дорівнює
lastReadEventKey; - немає активного Follow-up mail;
- останній закритий/відповіданий Follow-up mail відсутній або його час менший за час події статистики;
- після події статистики TU ще не відправляла нового листа.
Prime такого джерела не має.
Після успішної перевірки lastReadEventKey оновлюється незалежно від того, чи був створений таск, тому той самий statistics snapshot повторно не обробляється. Помилка API маркер не пересуває.
Післячатовий таймер
Закриття UnansweredMessage створює або замінює postChatSourceTaskId і postChatDueAt через 600–1200 с. Новий Unanswered скасовує старий таймер; закриття нового створює новий.
Коли час настав, сервіс читає mail history. Якщо після source-таска TU вже відправила лист, маркер видаляється. Інакше виконується спроба створення незалежно від online RU: post-chat FollowUpMail створюється і для offline RU.
Понад 5 Unanswered за 10 хвилин
При кожному закритті UnansweredMessage:
- Порахувати закриті Unanswered цієї пари за останні
10 хв. - Якщо їх більше
5і це закриття ще не дорівнюєlastBurstSourceTaskId, перевірити умови Follow-up mail. - Після успішної перевірки записати закриття як оброблене; якщо умови виконані — зробити одну спробу з шансом
50%.
Негативний результат теж залишається обробленим і після перезапуску повторно не рандомиться. Помилка API маркер не пересуває.
Chathouse notification
ONLINE_NOW/RECENT_PURCHASE без chat limit, але з mail limit проходить через ту саму фінальну перевірку.
Спільна фінальна перевірка
Усі джерела сходяться в один lock для TU+RU. Перед Task Factory перевірити:
- active favorite,
!isWhite, не freeloader і немає block; - немає
UnansweredMailабо активногоFollowUpMail; - mail-канал доступний: для Chathouse/Prime є mail limit; Golden окремого mail limit не має;
- після source-події TU не відправила нового листа.
Якщо одночасно спрацювали кілька джерел, mail history читається один раз і створюється не більше одного кандидата.
Запити
- Golden: один
getMail, окремої перевірки limit немає. - Chathouse: один точковий mail history; mail limit уже є в dialog snapshot.
- Prime: актуальні limits — окремий
POST /platform/chat/restriction; mail history може вимагатиcorrespondence/getіemails-history.
Якщо одночасно готові кілька причин однієї пари, ці відповіді використовуються спільно й не дублюються для кожної причини.
Збереження
Runtime-стан причин живе в пам’яті сервісу. Кожна зміна favorite.followUpMail одразу оновлюється локально та відправляється на Stack з idempotency key source task/statistics event. Помилка запису залишається в локальній durable-черзі й повторюється; повторний запуск відновлює стан зі Stack, Task history та невідправлених локальних змін.