Node.js Функция socket.send() не завершается перед выходом
В некоторых сценариях Node.js, которые я написал, я замечаю, что даже если последняя строка является синхронным вызовом, иногда она не завершается до выхода Node.js.
Я никогда не видел, чтобы оператор console.log
не запускался/завершался до выхода, но я видел, что некоторые другие утверждения не завершились до выхода, и я считаю, что они все синхронны. Я мог понять, почему обратный вызов асинхронной функции в этом случае не будет срабатывать.
Этот код является вызовом ZeroMQ .send()
следующим образом:
var zmq = require('zmq');
var pub = zmq.socket('pub');
pub.bindSync('tcp://127.0.0.1:5555');
setInterval(function(){
pub.send('polyglot');
},500);
Вышеприведенный код работает так, как ожидалось... но если я удалю setInterval()
и просто вызову его вот так:
var zmq = require('zmq');
var pub = zmq.socket('pub');
pub.bindSync('tcp://127.0.0.1:5555');
pub.send('polyglot'); //this message does not get delivered before exit
process.exit(0);
... Тогда сообщение не будет доставлено - программа, по-видимому, выйдет до завершения вызова pub.send()
.
Каков наилучший способ убедиться, что инструкция завершена до выхода из Node.js? Здесь будут работать отключающие крюки, но я боюсь, что это просто замаскирует проблему, так как вы не можете поместить все, что вам нужно, чтобы обеспечить запуск в завершающем режиме.
Эта проблема также может быть продемонстрирована следующим образом:
if (typeof messageHandler[nameOfHandlerFunction] == 'function') {
reply.send('Success');
messageHandler[nameOfHandlerFunction](null, args);
} else {
reply.send('Failure'); //***this call might not complete before the error is thrown below.***
throw new Error('SmartConnect error: no handler for ZMQ message sent from Redis CSV uploader.');
}
Я считаю, что это законная/серьезная проблема, потому что многим программам просто нужно публиковать сообщения, а затем умереть, но как мы можем эффективно обеспечить отправку всех сообщений (хотя и не обязательно полученных)?
EDIT:
Один (потенциальный) способ исправить это:
socket.send('xyz');
socket.close(); // supposedly this will block until the above message is sent
process.exit(0);
Ответы
Ответ 1
Погрузившись в zeromq.node, вы увидите, что Socket.send
просто подталкивает ваши данные к _outgoing
:
this._outgoing.push([msg, flags]);
... и затем вызывает _flush
iff zmq.ZMQ_SNDMORE не задано:
this._flush();
Похоже, _flush
фактически выполняет запись сокета. Если _flush()
терпит неудачу, он выдает ошибку.
Edit:
Я догадываюсь вызывать pub.unbind()
перед выходом, заставит _flush()
называться:
pub.unbind('tcp://127.0.0.1:5555', function(err) {
if (err) console.log(err);
process.exit(0); // Probably not even needed
});
Ответ 2
Я думаю, что простой ответ - метод socket.send()
на самом деле асинхронный, и поэтому мы видим поведение, которое я описал в OP. Тогда возникает вопрос: почему socket.send()
должен быть асинхронным - не может ли быть блокирующая/синхронная версия, которую мы могли бы использовать вместо этой цели, предназначенной для OP? Можем ли мы иметь socket.sendSync()
? K спасибо