Отмена работы, когда клиент ушёл
Вопрос
Клиент закрыл соединение, а обработчик продолжает делать три запроса к внешним API и тяжёлый запрос к БД. Как организуете отмену?
Попробуйте сами
Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.
Показать ответ и разбор
Коротко
Что должно прозвучать в ответе
Создаю `AbortController` на запрос и вызываю `abort()` по событию `close` у запроса или ответа
Передаю `signal` во все операции: `fetch`, клиенты БД и SDK, которые его поддерживают, `timers/promises`, свои функции
Объединяю сигналы: клиент ушёл или общий дедлайн (`AbortSignal.any([req, AbortSignal.timeout(ms)])`)
Для запросов к БД отмена на стороне сервера: `statement_timeout` или отмена запроса через драйвер, иначе БД продолжит работу
Проверяю `signal.aborted` между шагами долгих циклов и не начинаю новые шаги
Важно различать: отмена чтения безопасна, а уже начатую запись нужно довести или откатить транзакцией
Что могут спросить следом
- Что делать с операцией, которая не поддерживает AbortSignal?
- Как пробросить сигнал в NestJS-сервис?
- Чем таймаут на стороне клиента отличается от statement_timeout?
Разбор
Стандартный механизм отмены в Node это AbortController. На каждый запрос создаю контроллер и вызываю abort(), когда соединение закрылось раньше ответа. Сигнал передаю во все операции, которые его понимают: fetch (undici), многие SDK, timers/promises, events.once, свои функции. Часто сигнал комбинирую с дедлайном через AbortSignal.any и AbortSignal.timeout, чтобы запрос не жил дольше разумного, даже если клиент ждёт. С базой отдельная история: отмена на клиенте не останавливает запрос на сервере БД, поэтому нужен statement_timeout или явная отмена запроса драйвером. В длинных циклах проверяю signal.aborted между шагами. И разделяю чтение и запись: чтение отменять безопасно, а запись либо доводится до конца, либо откатывается транзакцией, чтобы не оставить данные в половинчатом состоянии.
Ответьте сами, а не прочитайте
В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.
Предыдущий вопрос
AsyncLocalStorage для контекста запроса
Следующий вопрос
Необработанный отклонённый промис в Node 22