Подтвердить что ты не робот

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);
4b9b3361

Ответ 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 спасибо