Асинхронная обработка: что отправить в фон, а что оставить в чате
Синхронный вызов модели прост: отправили запрос, дождались ответа, показали пользователю. Пока задачи короткие, этого достаточно. Проблемы начинаются, когда обработка занимает минуту или когда таких задач сотня.
Признак, по которому выбирают режим
Признак простой, но его регулярно нарушают в обе стороны. Разбор загруженного файла делают синхронным — и пользователь смотрит на спиннер две минуты. Подсказку при вводе отправляют в очередь — и она приходит, когда человек уже закончил печатать.
Что даёт очередь
**Устойчивость к всплескам.** Пришло сразу двести задач — они встали в очередь, а не уронили сервис.
**Соблюдение лимитов.** Скорость обработки задаётся вами, а не тем, как быстро приходят задачи.
**Повторы без потерь.** Упавшая задача возвращается в очередь и обрабатывается снова, а не исчезает вместе с запросом пользователя.
**Приоритеты.** Пользовательские задачи проходят вперёд фоновых.
Что предусмотреть
- **Идемпотентность.** Задача может выполниться дважды: обработчик упал после вызова модели, но до записи результата. Проверяйте, не сделана ли работа уже.
- **Ограничение числа попыток.** Иначе задача с неисправимой ошибкой будет повторяться вечно и жечь бюджет.
- **Отдельная очередь для неудачных задач.** Туда уходит то, что не получилось после всех попыток, — оттуда это разбирают руками.
- **Срок жизни задачи.** Результат, который стал неактуален, лучше не считать вовсе.
- **Отмена.** Пользователь передумал — задача должна сниматься до вызова модели.
Отмена окупается быстрее всего в интерфейсах с быстрым переключением между запросами: брошенные задачи там легко составляют заметную долю счёта.
Как сообщать о результате
Три способа, от простого к сложному: письмо, уведомление в интерфейсе, обновление страницы в реальном времени.
Для большинства задач достаточно первого или второго. Важнее другое — показать статус. «Обрабатывается, обычно занимает около минуты» снимает большую часть обращений в поддержку.
Если задача идёт долго, показывайте прогресс по этапам, а не проценты. «Расшифровка завершена, готовим сводку» понятнее, чем полоса, застрявшая на сорока процентах.
Разделение потоков
Пользовательские и фоновые задачи должны идти по разным очередям с разными лимитами. Иначе ночной пересчёт каталога способен заблокировать чат на сайте.
Простейшая схема: две очереди, у фоновой жёстко ограниченная скорость, у пользовательской приоритет. При нехватке лимита замедляется фоновая, а не та, где кто-то ждёт ответа.
Пакетная обработка
Для больших однотипных объёмов есть третий режим — отложенная обработка со сниженной ставкой, которую предлагают некоторые провайдеры. Результат приходит не сразу, зато дешевле.
Подходит для ночных пересчётов, разметки данных и массовой генерации описаний. Не подходит ни для чего, что видит пользователь в момент работы.
Как устроен обработчик
Обработчик — обычный процесс, который в цикле берёт задачу из очереди, выполняет её и записывает результат. Несколько деталей отличают рабочую реализацию от учебной.
**Задача помечается взятой в работу.** Иначе второй обработчик возьмёт её же.
**У задачи есть срок выполнения.** Если обработчик упал, задача через заданное время возвращается в очередь, а не зависает навсегда.
**Результат пишется одной операцией вместе со снятием задачи.** Иначе возможно состояние, когда результат записан, а задача осталась в очереди.
**Количество обработчиков настраивается.** Это ваш основной рычаг: им регулируется и скорость, и расход.
Что мерить
Четыре величины показывают состояние системы почти полностью.
| Метрика | О чём говорит |
|---|---|
| Длина очереди | Успеваете ли за потоком |
| Время ожидания в очереди | Что чувствует пользователь |
| Доля задач в очереди неудачных | Есть ли системная поломка |
| Число повторов на задачу | Упор в лимиты или сбои провайдера |
Первую стоит вывести на видное место. Растущая очередь — единственный признак, по которому проблему видно заранее, до того как начнут жаловаться.
Отдельно настройте уведомление на очередь неудачных задач. Она должна быть пустой; всё, что там появилось, требует человеческого разбора, и чем раньше, тем лучше.
С чего начать
Возьмите самую долгую операцию в вашем продукте и переведите её в фон. Обычно это разбор загруженного файла или генерация длинного документа.
Одна такая правка убирает главную жалобу на скорость и заодно даёт готовый каркас: следующие фоновые задачи ложатся в него без дополнительной работы.
Стоит заранее решить и что показывать в интерфейсе, когда очередь длинная. Честная оценка вроде «перед вами двенадцать задач, обычно это около трёх минут» воспринимается заметно лучше, чем бесконечный индикатор. Оценка считается по средней скорости обработки за последний час — цифра неточная, но полезнее молчания.
И предусмотрите режим, в котором приём новых задач приостанавливается. Он понадобится при аварии у провайдера: лучше честно сказать, что обработка временно недоступна, чем набрать тысячу задач, которые всё равно не выполнятся.