#javascript #node.js #express #sockets #asynchronous
Вопрос:
У меня сложный процесс ввода-вывода, который я инициирую при использовании конечной точки. Эта конечная точка должна немедленно сообщить клиенту, что процесс запущен.
Тяжелая задача ввода-вывода может занять до 30 минут, поэтому мне интересно, в каком состоянии после этого остается соединение между сервером и клиентом res.json(...)
? Соединение с сокетом все еще открыто / полуоткрыто? Должен ли я в этом случае удалить сокет вручную после res.json(...)
этого ? Нормально ли, что heavyIO
задача завершается неудачно через 29 минут и переходит к экспресс-обработчику ошибок? И, наконец, является ли этот шаблон неверным, например, должен ли я обрабатывать задачи ввода-вывода совершенно по-другому?
Ниже приведен минимальный пример:
import express from 'express'
const app = express()
const asyncHandler = (handler) =>
(req, res, next) => Promise.resolve(handler(req, res, next)).catch(next)
const heavyIO = () =>
new Promise((resolve, reject) => setTimeout(() => Math.random() > 0.5 ? resolve() : reject('FAILED'), 1000))
app.get('/start', asyncHandler(async (_req, res) => {
// I want to be able to initiate the process and send back
// confirmation that the process has been started. I want the
// client to be able forget about this request.
res.json('ok...started process')
// Then we start to run the heavy IO process. Without the "await" this could
// lead to unhandled promise rejection.
// If this fails, the rejected promise will flow to express default
// error handling which is I think "finalhandler" by default.
// Because the headers as sent (res.headersSent === true) the error
// handler will log the error and destroy the socket connection.
// If this succeeds, the server will probably close the socket connection as well
// internally.
// Up until this point the socket has been open (or half-open?) so is this a problem?
// Does it mean that the client has been "up-keeping" this socket connection
// somehow or has/can it have been timed out before this succeeds or fails.
await heavyIO()
console.log(`FINISHED I/O at ${new Date().toISOString()}! Exiting handler...`)
}))
app.listen(8080)
Комментарии:
1. «было ли/может ли истечь время ожидания до того, как это произойдет успешно или не удастся». Клиент может прервать соединение. Но я не понимаю, зачем вам нужна связь после
res.json('ok...started process')
этого . Он может быть закрыт после этой строки.2. @jabaa это правда. Если ввод-вывод завершится успешно или завершится неудачно, мы, по крайней мере, не должны уведомлять клиента об обратном использовании этого соединения. Как мне закрыть соединение?
3. Я не понимаю, чего вы здесь пытаетесь достичь. Почему ты вообще держишь связь открытой? Почему вы используете
asyncHandler
иasync
? Зачем вамawait
эта функцияheavyIO
? После этого связь между клиентом и сервером отсутствуетres.json('ok...started process')
.4. Если вы закроете соединение, клиенту потребуется регулярно запрашивать статус. Для процесса, который занимает значительное время, поддержание соединения открытым, ничего не делая в течение 30 минут или более, кажется расточительным (для меня). Объединение через регулярные промежутки времени кажется более адекватным. Альтернативой может быть использование веб-сокетов для обеспечения всегда открытого канала связи между клиентом и сервером, который позволяет серверу отправлять обновления о ходе выполнения. Учитывая, что веб-сокеты более сложны и, следовательно, могут создавать свои собственные проблемы, я бы пошел с опросом.
5. @Tomalak Где вы видите общение после
res.json('ok...started process')
? Статус и заголовок будут отправлены. Будет отправлено ответное сообщение. Что вы хотите опросить?