Отключение работника кластера домена Node.js
Глядя на пример, приведенный на странице документации по домену nodejs: http://nodejs.org/api/domain.html, рекомендуемый способ перезапустить работника с использованием кластера - это вызвать сначала отключение в рабочей части и прослушать отключение. событие в мастер-части. Однако, если вы просто скопируете / вставите приведенный пример, вы заметите, что вызов disconnect() не завершает работу текущего работника:
Что происходит здесь:
try {
var killtimer = setTimeout(function() {
process.exit(1);
}, 30000);
killtimer.unref();
server.close();
cluster.worker.disconnect();
res.statusCode = 500;
res.setHeader('content-type', 'text/plain');
res.end('Oops, there was a problem!\n');
} catch (er2) {
console.error('Error sending 500!', er2.stack);
}
Я делаю запрос на получение / ошибка
- Запускается таймер: через 30 с процесс будет убит, если еще не
- Http-сервер выключен
- Рабочий отключен (но все еще жив)
- 500 страница отображается
Я делаю второй запрос на получение ошибки (до 30 с)
- Новый таймер запущен
- Сервер уже закрыт => сгенерировать ошибку
- Ошибка отлавливается в блоке "catch", и результат не отправляется обратно клиенту, поэтому на стороне клиента страница ожидает без какого-либо сообщения.
На мой взгляд, было бы лучше просто убить работника и прослушать событие 'exit' в мастер-части, чтобы снова разветвляться. Таким образом, ошибка 500 всегда отправляется во время ошибки:
try {
var killtimer = setTimeout(function() {
process.exit(1);
}, 30000);
killtimer.unref();
server.close();
res.statusCode = 500;
res.setHeader('content-type', 'text/plain');
res.end('Oops, there was a problem!\n');
cluster.worker.kill();
} catch (er2) {
console.error('Error sending 500!', er2);
}
Я не уверен насчет побочных эффектов, использующих kill вместо disconnect, но кажется, что disconnect ожидает закрытия сервера, однако кажется, что это не работает (по крайней мере, не так, как должно)
Я просто хотел бы получить отзывы об этом. Может быть веская причина, по которой этот пример написан так, что я пропустил.
Спасибо
РЕДАКТИРОВАТЬ:
Я только что проверил с curl, и он работает хорошо.
Однако ранее я проводил тестирование с Chrome, и кажется, что после отправки ответа 500, chrome выполняет второй запрос ДО того, как сервер действительно завершит работу.
В этом случае сервер закрывается и не закрывается (что означает, что рабочий также отключается без отключения), в результате чего второй запрос обрабатывается тем же рабочим, что и раньше:
- Это мешает серверу завершить закрытие
- Второй
server.close();
оцениваемая строка вызывает исключение, потому что сервер не закрыт. - Все последующие запросы будут вызывать одно и то же исключение, пока не будет вызван обратный вызов killtimer.
2 ответа
Я понял это, на самом деле, когда сервер закрывается и одновременно получает запрос, он останавливает процесс закрытия.
Таким образом, он все еще принимает соединение, но больше не может быть закрыт.
Даже без кластера этот простой пример иллюстрирует это:
var PORT = 8080;
var domain = require('domain');
var server = require('http').createServer(function(req, res) {
var d = domain.create();
d.on('error', function(er) {
try {
var killtimer = setTimeout(function() {
process.exit(1);
}, 30000);
killtimer.unref();
console.log('Trying to close the server');
server.close(function() {
console.log('server is closed!');
});
console.log('The server should not now accepts new requests, it should be in "closing state"');
res.statusCode = 500;
res.setHeader('content-type', 'text/plain');
res.end('Oops, there was a problem!\n');
} catch (er2) {
console.error('Error sending 500!', er2);
}
});
d.add(req);
d.add(res);
d.run(function() {
console.log('New request at: %s', req.url);
// error
setTimeout(function() {
flerb.bark();
});
});
});
server.listen(PORT);
Просто беги:
curl http://127.0.0.1:8080/ http://127.0.0.1:8080/
Выход:
New request at: /
Trying to close the server
The server should not now accepts new requests, it should be in "closing state"
New request at: /
Trying to close the server
Error sending 500! [Error: Not running]
Теперь одиночный запрос:
curl http://127.0.0.1:8080/
Выход:
New request at: /
Trying to close the server
The server should not now accepts new requests, it should be in "closing state"
server is closed!
Так, например, с помощью chrome, выполняющего еще 1 запрос к значку, сервер не может завершить работу.
Сейчас я буду продолжать использовать worker.kill(), который заставляет работника не ждать остановки сервера.
Я столкнулся с той же проблемой около 6 месяцев назад, к сожалению, у меня нет кода для демонстрации, как это было с моей предыдущей работы. Я решил это путем явной отправки сообщения работнику и одновременного вызова разрыва соединения. Отключение не позволяет работнику приступить к новой работе, и в моем случае, когда я отслеживал всю работу, которую выполнял работник (это было для службы загрузки, для которой выполнялись длительные загрузки), я смог дождаться завершения всех из них, а затем выход с 0.