Как реализована обратная связь с клиентом при долгой обработке файла
Что проверяют
Умеете ли вы превратить долгую синхронную операцию в асинхронную так, чтобы клиент видел прогресс, а задача переживала перезапуск сервиса. Следом обычно спрашивают, что будет с задачей, если экземпляр сервиса упадёт посреди обработки.
Как отвечать
Расскажите о своём случае с цифрами: размер файлов, время обработки, сколько задач в час. Каркас решения на Go:
- приём: файл не держится в памяти. Либо поток сразу уходит в S3-совместимое хранилище, либо клиент грузит туда сам по presigned URL. Размер ограничивает
http.MaxBytesReader; - ответ: сервер создаёт задачу в базе и сразу отвечает
202 Acceptedс идентификатором и заголовкомLocation: /jobs/{id}; - обработка: пул воркеров с ограниченным числом горутин читает задачи из очереди (RabbitMQ, Kafka, NATS или таблица в PostgreSQL с
FOR UPDATE SKIP LOCKED). Прогресс, статус и текст ошибки пишутся в хранилище, а не в канал внутри процесса; - обратная связь: самый простой вариант, polling
GET /jobs/{id}. Для живого прогресса подходит SSE:Content-Type: text/event-streamиhttp.Flusherпосле каждого события. WebSocket нужен, если клиенту есть что отправлять обратно, а внешним системам удобнее вебхук по завершении; - надёжность: у задачи есть конечные статусы
doneиfailed, таймаут на зависшую обработку и лимит повторов. Приhttp.Server.Shutdownворкеры дописывают текущую задачу или возвращают её в очередь.
Если так делать не приходилось, честно скажите об этом и покажите, как спроектировали бы решение: начать с простого polling и объяснить, в какой момент переходить на SSE.
Где спотыкаются
Запускают go process(file) прямо из обработчика и хранят статус в map в памяти. После рестарта всё теряется, а на двух репликах запрос статуса попадает не на тот экземпляр.
Передают в фоновую горутину r.Context(). Он отменяется, как только обработчик вернул ответ; нужен свой контекст, например context.WithoutCancel с отдельным таймаутом.
Держат HTTP-соединение открытым на всё время обработки. Прокси обрывает его по таймауту, в Nginx proxy_read_timeout по умолчанию 60 секунд, и клиент так и не узнаёт, выполнилась ли задача.