2015-04-27 13 views
17

W niektórych skryptach Node.js, które napisałem, zauważam, że nawet jeśli ostatnia linia jest połączeniem synchronicznym, czasami nie kończy się przed węzłem. js wychodzi.Funkcje Node.js socket.send() nie kończą się przed zakończeniem

Nigdy nie widziałem, aby instrukcja console.log nie działała/kończyła się przed wyjściem, ale widziałem, że inne instrukcje nie zostały zakończone przed wyjściem i uważam, że wszystkie są synchroniczne. Mogłem zrozumieć, dlaczego wywołanie funkcji asynchronicznej oczywiście nie zaszło w tym przypadku.

Kod w pytaniu jest ZeroMQ .send() wezwanie tak:

var zmq = require('zmq'); 
    var pub = zmq.socket('pub'); 

    pub.bindSync('tcp://127.0.0.1:5555'); 

    setInterval(function(){ 
     pub.send('polyglot'); 
    },500); 

Powyższy kod działa zgodnie z oczekiwaniami ... ale jeśli usunąć setInterval() i po prostu nazwać tak:

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

... Następnie wiadomość nie zostanie dostarczona - program prawdopodobnie zakończy działanie przed zakończeniem połączenia pub.send().

Jaki jest najlepszy sposób, aby upewnić się, że wyciąg zakończy się przed wyjściem z Node.js? Haki zamykające zadziałają tutaj, ale obawiam się, że to tylko maskowałoby problem, ponieważ nie można umieścić wszystkiego, co jest potrzebne, aby zapewnić działanie w haku wyłączającym.

Problem ten można również przedstawić w ten sposób:

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.'); 
    } 

Wierzę, że to jest legit poważny problem/ponieważ wiele programów wystarczy opublikować wiadomości, a potem umrzeć, ale w jaki sposób możemy skutecznie zapewnić wszystkich wiadomości są wysyłane (choć niekoniecznie odbierane)?

EDIT: One (potencjalny) sposób naprawić to zrobić:

socket.send('xyz'); 
socket.close(); // supposedly this will block until the above message is sent 
process.exit(0); 
+0

według projektu skrypt synchroniczny zostanie uruchomiony do zakończenia, chyba że proces.Metoda exit() jest wywoływana, więc w tym przypadku będziesz musiał pokazać jakiś kod. W przeciwnym razie będzie po prostu zgadywać, co może nie być prawdą. –

+2

Nie można zagwarantować zakończenia asynchronizacji w haku zamknięcia. – SLaks

+1

może spróbować owijać go w setTimeout z 0? –

Odpowiedz

8

nurkowanie w zeromq.node, można zobaczyć, co Socket.send tylko pushes your data to _outgoing:

this._outgoing.push([msg, flags]); 

... a potem calls _flush iff zmq.ZMQ_SNDMORE is unset:

this._flush(); 

Wygląda na to, że _flush is actually doing the socket write. Jeśli nie powiedzie się _flush(), it emits an error.

Edit:

Zgaduję nazywając pub.unbind() przed wyjściem, zmusi _flush() się nazywać:

pub.unbind('tcp://127.0.0.1:5555', function(err) { 
    if (err) console.log(err); 
    process.exit(0); // Probably not even needed 
}); 
+0

Nie sądzę, że "przedwczesne" wyjście spowoduje, że funkcja _flush() zakończy się niepowodzeniem. Nic nie jest awarią, po prostu mój proces node.js nie wie, że musi poczekać na zakończenie kodu zmq –

+0

Proszę zobaczyć moje edycje - zamiast process.exit() ten sam problem może się pojawić, jeśli zgłoszymy błąd . –

0

Myślę, że odpowiedź jest prosta metoda jest socket.send() Fakt asynchroniczny i dlatego widzimy zachowanie opisane w PO. Pytanie brzmi więc: dlaczego socket.send() musi być asynchroniczne - czy nie może istnieć blokująca/synchroniczna wersja, którą moglibyśmy użyć zamiast tego w zamierzonym celu w OP? Czy możemy prosić o socket.sendSync()? K dzięki

Powiązane problemy