Таски — цільовий дизайн

Цільовий набір тасків єдиного воркспейсу: що це за таски, яке апі є в кожного проекту і як цим апі зробити кожен таск. Рішення і відкриті питання — Plan; as-is деталі проходів — Unification і Current State.

Цільовий набір (з обговорення)

Follow-up = колишній NeedToWrite. Таски сортуються по пріоритету (правила — питання 1 у Plan).

  • 120 с · Unanswered message — вхідні повідомлення в чаті.
  • 600 с · Unanswered mail — вхідні листи.
  • 43200 с · Unanswered e-mail — вхідні імейли (з моменту отримання листа).
  • 300 с · Follow-up message — нагадати про себе, щоб продовжити чат:
    1. після відповіді на unanswered — створюється рандомно через 60–180 с, лімітована кількість із шансом (1-й — 100%, 2-й — 75%, 3-й — 50%);
      • логіку вести не в рамках сесії, а відносно діалогу;
      • якщо RU офлайн — тримати логіку, поки не спрацює умова 2;
    2. останнє повідомлення від TU понад 3600 с тому;
    3. нотифікація від Chathouse.
  • 900 с · Follow-up mail — нагадати про себе листом; по фрілоадерах не створюється:
    1. останній лист від TU понад 6 год тому;
    2. лист від TU прочитано RU;
    3. (післячатовий - можна писати офлайн РЮ) створюється через 600–1200 с після останньої відповіді на unanswered message, якщо після неї не було відправлених листів;
    4. якщо за 10 хв від RU прийшло понад 5 повідомлень — при закритті кожного unanswered message створюється з шансом 50%;
    5. нотифікація від Chathouse, якщо нема лімітів у чаті.
  • 300 с · Open Limits:
    1. повністю порожній діалог з відкритими лімітами;
    2. останнє повідомлення — айсбрейкер;
    3. системне повідомлення про відкриття лімітів.
  • 300 с · Open Limits (Captcha) — чат-реквести.
  • 300 с · Like — будь-які безкоштовні дії типу лайка, вінка, розочки.

Приставка VIP — по всіх клієнтах, колір залежить від глобальних витрат RU за останні 30 днів: червоний — 300 · зелений — 900 $.

План реалізації

Unanswered message · 120 с

Вхідні повідомлення в чаті.

ЛогікаGolden (в Electron)ChathousePrime
СокетreceivePrivateMessageSendMessageSent
Колонка Unanswered з APIcheck chatcheck chat
При перегляді активних фаворитів онлайнгенерація Follow-up підстрахує

check chat — перевірка колонки з апі при логіні, при реконекті сокета і, можливо, раз на 30 хв. Колонки різні: Chathouse — вкладка new, одна на чат і листи; Prime — окрема чат-вибірка unanswered.

Unanswered mail · 600 с

Вхідні листи.

ЛогікаGolden (в Electron)ChathousePrime
СокетSend (тип inmail_message)email
Статистикабонуси по типах EmailSend*бонуси по типах inmail_send*❌ — статистики нема
Апі поштиcheck mail

EmailSend* — типи EmailSend / EmailSendSatellite / EmailSendBonusCoins: RU надіслав лист → перевіряємо цей діалог.

inmail_send* — типи inmail_send / inmail_photo_send / inmail_video_send: бонус за лист від RU → перевіряємо цей діалог. Зараз ці типи ніде не читаються — логіка буде нова. TODO: уточнити, на які типи точно реагуємо.

check mail — у Prime апі пошти окреме, не як у чаті; сокет є → перевірка тільки при логіні, а не постійна, як зараз на проді.

Follow-up message · 300 с

Нагадати про себе, щоб продовжити чат. За замовчуванням створюється тільки активним фаворитам онлайн, яких не заблокували ми чи вони нас.

ЛогікаGolden (в Electron)ChathousePrime
Ланцюжок після unansweredнаша логіканаша логіканаша логіка
Останнє від TU понад 3600 снаші фаворити; онлайн — апі онлайн-RUнаші фаворити; онлайн — зі скролу колонокнаші фаворити; онлайн — зі скролу колонок
Нотифікація сокетомnew_notification

Фаворити й онлайн — фаворитів обчислюємо і тримаємо на своїй стороні (рішення — Plan); з апі оновлюємо тільки онлайн і хто кого заблокував. Golden має апі онлайн-RU; колонки Chathouse/Prime і так скролитимуться, щоб тримати онлайн RU, — з цих даних фільтруємо активних фаворитів онлайн, окремо для цього таска нічого не скролимо. Умову «останнє від TU понад 3600 с» перевіряємо прямо в цих проходах онлайну — окремого проходу для неї нема.

Ланцюжок — повністю наша логіка, стан ведемо по діалогу, не в рамках сесії. Список тасків і список повідомлень скоріш за все не збігатимуться 1 в 1 — важливі два часи: коли написав RU і коли TU його закрила (це і є жовтий Unanswered таск з часом закриття). Точка відліку ланцюжка — час закриття Unanswered message (теоретично він може бути через скільки завгодно від моменту, як написав RU). Від нього таск через рандомні 60–180 с; 2-й і 3-й кроки — ті самі 60–180 с від попередньої спроби; кроки лімітовані з шансом (1-й — 100%, 2-й — 75%, 3-й — 50%). Це три спроби створити таск, а не три гарантовані таски — шанс може не випасти, тасків може бути й один. Ланцюжок працює по тасках: якщо оператор пише сам, без таска, — не важливо, не враховуємо. У стані ланцюжка фіксуємо номер спроби та її час, і оновлюємо їх не при створенні таска, а при його фактичному закритті; якщо спроба без таска (шанс не випав) — у момент перевірки. Бо таск можна створити, не закрити і вийти; оператор може його ігнорувати; або RU вийде в офлайн і таск закриється як прострочений. Ланцюжок обмежений у часі: стосується фаворитів, які писали нам недавно, — до ~1 год; далі діалог переходить у логіку «понад 3600 с». Варіанти життя ланцюжка:

  • новий Unanswered message стирає інфо про спробу й час — нова відповідь TU запустить новий ланцюжок (може повторюватись знову і знову);
  • ланцюжок закрили повністю — всі кроки відпрацювали;
  • RU офлайн у момент, коли таймер дійшов до таска — таск не створюємо, спробу й час не оновлюємо, таймер по колу не крутимо: щойно RU зайде в онлайн — таск одразу; так тримаємо, поки не спрацює умова «понад 3600 с»;
  • у момент створення таска — знову перевірити онлайн RU і ліміти.

Нотифікація (Chathouse) — сокет пінгує (ONLINE_NOW / RECENT_PURCHASE) → пробуємо створити таск: якщо тасків по діалогу нема — створюємо; якщо діалог уже ведеться — нічого.

Відновлення після перезапуску — ланцюжки треба не лише вести в реальному часі, а й відновлювати після перезапуску програми. Джерело — історія тасків + інформація про спроби у фавориті. Приклад: в історії Unanswered message о 13:00 і закритий Follow-up о 13:30 → RU онлайн → рандомимо 60–180 с на наступний крок. Кроки при цьому розтягуються відносно повідомлення RU (від нього може пройти ~3 год, а від TU піде лише 3 повідомлення) — по ідеї це ок. Це має працювати і між операторами: перезайшов змінщик — ланцюжки підтягуються.

Пропозиції:

  • Найпростіше — писати стан ланцюжка у фаворита (коли остання спроба і скільки їх було); але не хочеться оновлювати купу даних — подумати.

Сценарії (чернетка; за основу — історія тасків + стан ланцюжка у фаворита: «спроба N, час T»):

stateDiagram-v2
    state "Очікування таймера" as wait
    state "Перевірка" as check
    state "Follow-up таск" as task
    [*] --> wait: TU закрила Unanswered — фіксуємо час закриття
    wait --> check: рандом 60–180 с минув
    check --> wait: RU офлайн — чекаємо заходу в онлайн, тоді таск одразу
    check --> wait: шанс не випав — спроба +1, час = перевірки
    check --> task: шанс випав (100/75/50%) — створюємо таск
    task --> wait: таск закрито — спроба +1, час = закриття
    wait --> [*]: 3 спроби або ~1 год — діалог далі веде «понад 3600 с»
    note right of wait
        Новий Unanswered у будь-який момент:
        стан стирається, ланцюжок піде заново
    end note
  1. Написав RU (новий Unanswered).
    • Чистимо стан ланцюжка у фаворита: спроба й час → null.
    • Це автоматично рве поточний таймер і логіку спроб.
  2. TU закрила Unanswered.
    • Оновлюємо у фаворита час = закриття таска.
    • Запускаємо таймер рандом 60–180 с.
  3. Перезайшли в програму до 1-го Follow-up.
    • В історії — закритий Unanswered, у фаворита — час без спроб.
    • Минуло < 180 с від часу закриття → рандомимо таймер і продовжуємо.
    • Минуло від 180 с до ~1 год → таск одразу.
    • Минуло понад ~1 год → ланцюжок не відновлюємо, діалог уже в логіці «понад 3600 с».
  4. 1-й Follow-up створено й закрито.
    • При закритті: спроба 1, час = закриття; таймер на 2-у спробу.
    • Таймер спрацював → шанс 75%: випав → створюємо таск; не випав → спроба 2, час = перевірки, таймер на 3-ю (50%).
  5. Таймер спрацював, RU офлайн.
    • Таск не створюємо, стан не чіпаємо, таймер по колу не крутимо.
    • Щойно RU зайде в онлайн — таск одразу.
  6. Невдала спроба → перезайшли.
    • У фаворита вже зафіксовано спробу N і час перевірки.
    • Відновлення як у сценарії 3 (якщо спроб < 3): < 180 с → таймер, до ~1 год → таск одразу.
  7. RU офлайн уже 15 хв на 1-й спробі.
    • Чекаємо за сценарієм 5 — без повторних таймерів.
    • Повернувся онлайн → таск одразу.
    • Не повернувся до ~1 год → ланцюжок завершився, діалог підхопить «понад 3600 с» (їй теж потрібен онлайн).
  8. 1-й закрито, 2-а і 3-я — невдача.
    • У фаворита послідовно: спроба 1 (час закриття) → спроба 2 (час перевірки) → спроба 3 (час перевірки).
    • Ланцюжок завершено; стан лежить, поки RU не напише знову (сценарій 1).
  9. Посеред ланцюжка написав RU.
    • Сценарій 1: стан чиститься, таймер рветься.
    • TU закрила новий Unanswered → ланцюжок заново (сценарій 2).
  10. Блок посеред ланцюжка (ми RU чи RU нас).
    • Логіка перевірки блоків видаляє відкритий таск і чистить таймер зі станом ланцюжка.

Рішення — з чого будується Follow-up message

Тип побудований тільки на історії тасків та оновленні онлайну — без додаткових запитів на апі:

  1. Історія тасків — знаходимо останній Unanswered message, бачимо, коли він закритий → фільтруємо діалог у пул для логіки ланцюжків.
  2. Фаворити — тут зберігаємо порядок ланцюжка і останній час його генерації (на випадок негативного рандому).
  3. Стан RU онлайн — окрема логіка тримає актуальний онлайн: Golden — окреме апі (15 с), Chathouse і Prime — сервіс скролу онлайн-діалогів (60 с).

З цього фільтруємо діалоги під умови ланцюжків: є час початку ланцюжка, час закриття останнього Follow-up, час, коли може створитись наступний, і розуміння, коли діалог перевалює за годину в іншу логіку. Умова «останнє повідомлення понад 60 хв» перевіряється там само — при скролі онлайну.

Follow-up mail · 900 с

Нагадати про себе листом. За замовчуванням створюється тільки активним фаворитам онлайн, яких не заблокували ми чи вони нас, і які не фрілоадери. Єдиний виняток з онлайну — післячатовий мейл-таймер: він може створити таск і для офлайн RU.

ЛогікаGolden (в Electron)ChathousePrime
Лист від TU понад 6 годскрол листів по активних фаворитах онлайн — getMailскрол листів по активних фаворитах онлайн — getInmailsChainскрол листів по активних фаворитах онлайн — апі пошти
Лист від TU прочитано RUстатистика: EmailRead / OpenAttachFileSatelliteстатистика: inmail_read*❌ — статистики нема (питання 1)
Мейл-таймер після відповіді на unansweredнаша логіканаша логіканаша логіка
Понад 5 unanswered за 10 хвнаша логіканаша логіканаша логіка
Нотифікація сокетом (нема чат-лімітів)new_notification

inmail_read* — типи inmail_read / inmail_photo_read / inmail_video_read; сьогодні вже використовуються для мейл-тасків.

Фрілоадери — критерії з рішення у Plan: Chathouse — платить лише бонусами; Prime — менше 11 платних дій; Golden — «бонусні» фаворити (сума 0).

Мейл-таймер після відповіді — через 600–1200 с після останньої відповіді на unanswered message, якщо після неї не було відправлених листів. Логіка схожа на ланцюжки Follow-up message: і в реальному часі, і при перелогіні у нас є інфо про закритий unanswered message і про Follow-up mail після нього — додатково треба дивитись переписку листів, як в умові «понад 6 год». Наявність листа перевіряємо перед самим створенням таска, а не в момент створення таймера. Важливо: рахуємо саме відправку листа, а не мейл-таск — лист могли відправити й без таска. Працює і для офлайн RU — єдиний виняток із дефолту онлайн.

Понад 5 unanswered за 10 хв — рахуємо закриті unanswered-таски за 10 хв: перевалило за 5 → логіка вмикається, ні — вимкнена (спілкування по черзі і тригерить її; RU написав 3 підряд — це один таск). Коли ввімкнена — при закритті кожного unanswered просто намагаємось зробити Follow-up mail з шансом 50%, якщо це можливо. Ця умова і мейл-таймер постійно взаємодіють: закриття unanswered-таска тригерить і таймер, і пряме створення.

Нотифікація (Chathouse) — та сама new_notification, що в чатовому: якщо чат-лімітів нема → пробуємо мейл-таск.

Рішення — з чого будується Follow-up mail

  1. Історія тасків — закритий unanswered message і Follow-up mail після нього (мейл-таймер) + лічильник unanswered за 10 хв (вмикає «понад 5»).
  2. Активні фаворити онлайн — пул, по якому скролимо переписку листів (умова «понад 6 год»).
  3. Переписка листів — скрол по пулу + точкова перевірка наявності листа перед самим створенням таска.
  4. Статистика прочитання — Golden і Chathouse; Prime — питання 1.
  5. Стан RU онлайн — той самий сервіс, що в Follow-up message; виняток — мейл-таймер працює і для офлайн RU.
  6. Нотифікація Chathouse — сокет, коли нема чат-лімітів.

Питання 1 — прочитання листа на Prime

Статистики прочитання на Prime нема. Або цієї умови там не буде, або треба регулярно перевіряти всі листи і фіксувати прочитання в БД — складнувато. Вирішити.

Питання 2 — межі мейл-таймера після unanswered

Чи чистить новий unanswered message таймер і цю логіку (як у чатовому ланцюжку)?

Open Limits · 300 с

Порожній діалог з відкритими лімітами — написати першими. Golden концепту лімітів не має — тип не застосовується.

ЛогікаGolden (в Electron)ChathousePrime
Порожній діалог / взаємний лайквкладка new — ще не створений діалог (id=null, без повідомлень) або взаємний лайк
Останнє system + є лімітисокет створення діалогу + скрол active
Останнє — айсбрейкерзакоментована логіка LimitsAreOpenedAfterIcebreakerMessage — реанімувати й тестити

Скрол Prime (as-is) — це не онлайн-колонка, а окремий прохід criteria active зі stateful-курсором: 1 сторінка (15 діалогів) за тік ~120 с, крок за кроком назад до 7 днів, потім курсор скидається. Сокет і скрол ведуть в одну умову: останнє повідомлення system + є ліміти + не заблокований, з VIP-дедупом; ліміти перевіряються живим запитом обмежень (значення в списку діалогів може бути кешоване). Сокет-подія «system opened limits» в коді є, але її обробка закоментована.

Chathouse — та сама вкладка new, що вже крутиться для Unanswered/Like, — окремого проходу не треба.

Айсбрейкер на Prime — логіки не буде. У списку діалогів айс — звичайне message без жодної мітки.

Питання 3 — як крутити Open Limits

По ідеї це теж перевіряємо, коли крутимо онлайн-колонку. Але на Prime порожні діалоги з типом system живуть у вибірці active (не online) — лишаємо окремий скрол зі stateful-курсором, як зараз, чи чіпляємо до спільних проходів?

Like · 300 с

Будь-які безкоштовні дії типу лайка, вінка, розочки. Логіка 1 в 1 як в Unanswered message — тільки тип дії в сокеті чи в останньому повідомленні не смс, а лайк і подібні.

ЛогікаGolden (в Electron)ChathousePrime
СокетreceivePrivateMessage — 🌹Send — лайк по тілу повідомленняMessageSent — лайк-типи
Колонка Unanswered з APIcheck chatлайки тільки в [] (all)

Лайк-типи — Prime: likephoto / wink / like_newsfeed_post; Chathouse — лайк визначається по тілу повідомлення; Golden — текст 🌹.

Prime — лайки у вибірках. У вибірці active (скрол діалогів) лайків не буде — вони в [] (all): схоже, criteria [] доведеться крутити по-любому, а active тоді лишається тільки для Open Limits (system-діалоги). Що і як краще крутити — подумати (питання 5). TODO: as-is код ловить like-типи у вибірці unanswered — звірити, чи лайки справді туди не потрапляють.

Питання 4 — доля LikeMail (Prime)

У новому наборі LikeMail нема. Prime сьогодні має окремий таск: фаворит лайкнув, чат-ліміти вичерпані, лист ще є → таск написати листом. Зливаємо це в Like чи прибираємо? TODO: вирішити (мабуть так). Важливо: ця крутілка ще й перебирала дії фаворитів і оновлювала їх — поки це потрібно (див. питання 5).

Зведення проходів — що крутимо

Ціль — крутити якомога менше, щоб менше запитів на апі, але щоб логіки працювали правильно.

ПрохідКрутимоДля чого
Chathouse
вкладка all + is_onlineпостійноонлайн RU, фаворити, Follow-up «понад 3600 с»
вкладка newcheck chatUnanswered чат/мейл, Like, Open Limits
вкладка savedне крутимо
Prime
criteria [active, online]постійноонлайн RU, фаворити, Follow-up «понад 3600 с»
criteria unansweredcheck chatUnanswered чат (Like — TODO, див. Like)
пошта inbox_unansweredcheck mailUnanswered мейл
criteria activeпитання 3Open Limits
criteria bookmarkedне крутимо — фаворити тепер у нас
criteria [] (всі діалоги)схоже, крутимо — лайки видно тільки тут (питання 5)as-is годував LikeMail і бутстрап фаворитів

Golden колонок не має — крутиться апі онлайн-RU і точкові запити по пулу фаворитів (chatHistory, getMail).

Питання 5 — criteria [] (всі діалоги) на Prime

Чи знадобиться прохід усіх діалогів для іншої логіки? As-is він робив три речі: одноразовий бутстрап фаворитів при першому логіні TU (повна історія), сендер-автолист нефаворитам і LikeMail (питання 4). Якщо фаворитів рахуємо у себе — бутстрап першого запуску TU все одно звідкись треба брати.

Питання 6 — таймери чи тіки

Відчуття, що проект треба будувати не на таймерах, як зараз (усе на setTimeout), а на тіках: робити тіки і по порядку звіряти логіки — але якось правильно. Проговорити.

Зв’язки

  • Plan — рішення і відкриті питання воркспейсу.
  • Unification — as-is механіка проходів і сокет-тригерів.
  • Current State — as-is по проектах (таймери, закриття).