Отключение работника кластера домена 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);
}
  1. Я делаю запрос на получение / ошибка

    • Запускается таймер: через 30 с процесс будет убит, если еще не
    • Http-сервер выключен
    • Рабочий отключен (но все еще жив)
    • 500 страница отображается
  2. Я делаю второй запрос на получение ошибки (до 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 выполняет второй запрос ДО того, как сервер действительно завершит работу.
В этом случае сервер закрывается и не закрывается (что означает, что рабочий также отключается без отключения), в результате чего второй запрос обрабатывается тем же рабочим, что и раньше:

  1. Это мешает серверу завершить закрытие
  2. Второй server.close(); оцениваемая строка вызывает исключение, потому что сервер не закрыт.
  3. Все последующие запросы будут вызывать одно и то же исключение, пока не будет вызван обратный вызов 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.

Другие вопросы по тегам