Як зберегти чат живим, коли телефон засинає
Агент Mythex може працювати хвилинами над одним запитом, і ви, можливо, стежите за цим з телефону — який блокується, перемикає застосунки і змінює мережу, поки працює агент. Дві помилки призводили до проблем. В одній чат вважав кожен сигнал «сторінка знову видима» доказом того, що з'єднання загинуло, і зациклювався, поки не застрягав на «Підключення…». В іншій телефон, що проспав першу відповідь нового чату, повертався лише з першими кількома фрагментами відповіді, поки сторінку не оновлювали вручну. Обидві виправлено.
Як чат стежить за працюючим ходом
Поки агент працює, чат тримає відкритим потік від наших серверів: кожен крок — думка, виклик інструмента, фрагмент відповіді — надходить як подія. Якщо потік обривається, чат перепідключається, а сервер відтворює останні події з буфера, який зберігає останні 120 секунд. Коли хід завершується, чат також запитує у сервера збережену історію й узгоджує те, що показав, із тим, що збережено. Цей останній крок ловить усе, що потік пропустив.
Щоб відрізнити живе з'єднання від мертвого, коли нічого не відбувається, сервер надсилає маленький «пінг» кожні 15 секунд.
Помилка 1: пробудження вбивало справний потік
Браузери повідомляють сторінці, коли вона знову стає видимою: після перемикання вкладки, після розблокування екрана. Ми використовували це як привід перевірити з'єднання — фактично перервати потік і перепідключитися, припускаючи, що він загинув, поки сторінка була прихованою.
На телефонах і у вбудованих браузерах такі події спрацьовують набагато частіше, ніж потоки справді вмирають: при кожному перемиканні вкладки, при кожному розблокуванні, а в деяких вбудованих браузерах — майже кожні пару секунд. Кожна з них переривала цілком справний потік. Чат перепідключався, відтворював події, знову переривався і врешті сидів на «Підключення…». Потім він повідомляв, що хід завершився, хоча агент ще працював.
Виправлення: судити про потік за тим, чи він передає дані
Тепер чат записує, коли потік кожного проєкту востаннє щось отримував — і події, і пінги. Сигнал «знову видима» перериває потік, лише якщо він мовчить 25 секунд: довше за інтервал пінгів плюс повільний мережевий перехід, тож живий потік ніколи не потрапляє під цю умову. Тести перевіряють, що пінг вважається ознакою життя, а потік, який щойно пінгував, не вважається мертвим.
Правило, яке ми з цього винесли: видимість сторінки говорить про сторінку, а не про мережеве з'єднання. Запитуйте з'єднання.
Помилка 2: півтори відповіді після пробудження телефона
Цю помилку ми могли відтворити щоразу в симуляторі iOS:
- Почніть новий чат і надішліть запит, який займе деякий час.
- Дайте телефону заснути під час збирання.
- Поверніться, коли хід уже завершився і двохвилинний буфер відтворення минув.
Чат показував перші кілька блоків відповіді як завершені — і залишався таким, поки ви не оновлювали сторінку.
Чому
Новий чат не має треду — збереженої розмови — доки перше повідомлення не створить його. Це відбувається всередині функції відправки, після того, як відправка вже захопила крок узгодження, який ще вважав, що треду немає. Тож наприкінці першого ходу в новому чаті узгодження бачило відсутність треду і мовчки повертало результат, нічого не запитуючи.
Зазвичай ніхто цього не помічав, бо потік і так доставляв увесь хід. Але телефон, що проспав хід і повернувся після того, як 120-секундний буфер відтворення минув, не міг отримати відсутні події з потоку — а узгодження, яке мало заповнити прогалину, ніколи не запускалося.
Виправлення
- Відправка повідомляє узгодженню, якому треду належить хід, тож перший хід нового чату узгоджується як будь-який інший. Якщо до того, як прийде відповідь, ви відкрили інший чат, результат відкидається, а не показується не в тому місці.
- Невдалe узгодження повторюється. Телефон, що прокидається на поганому з'єднанні, може виявити, що хід уже завершився, але не зміг його отримати. Тепер це запам'ятовується, і чат запитує знову, коли вкладка знову показується або мережа повертається.
- «Працював» — чесне. Кожна відповідь показує, скільки часу агент працював. Якщо вкладка так і не побачила серверного повідомлення про завершення ходу, вона раніше заповнювала це власним годинником, який йшов від натискання «Надіслати» до пробудження телефона, включно з часом відсутності. Тепер ця цифра позначена як оцінка і замінюється збереженою тривалістю, щойно прийде історія.
Що ми з цього винесли
- Тестуйте на пристрої, яким користуються люди, так, як вони ним користуються. Обидві помилки жили в проміжку між «потік, який працює» і «телефон у кишені».
- Запасний варіант, який ніколи не запускається, не є запасним. Крок узгодження існував саме для цього випадку, але мовчки його пропускав.
- Повторюйте і відновлення. Момент пробудження телефона часто є моментом, коли його з'єднання найгірше.
- Не показуйте припущення як факт. Тривалість, виміряна за іншим годинником, гірша за відсутність даних; позначте її або замініть.
Ця ж робота заодно прибрала кілька речей, які ви помітите під час роботи ходу: кроки з командами оболонки тепер позначаються командою, яка виконує роботу, а не cd; скриншоти в чаті зберігають верхній лівий кут сторінки і вміщуються в колонку; новий проєкт отримує згенеровану назву без оновлення сторінки.
Якщо ви створюєте власний застосунок для телефонів, наші гайди як створити застосунок, зручний для мобільних і нативні застосунки проти прогресивних веб-застосунків пояснюють основи. Більше про сам чат — у документації про чат.