2016-05-09 10 views
3

Basierend auf den Antworten auf this question, versuche ich herauszufinden, warum mehrere Arbeiter server.listen() auf dem gleichen Port/Adresse anrufen keine Probleme verursacht, aber mit einem alten Worker-Aufruf server.close() gefolgt von einem server.listen() auf dem gleichen Port wird wiederholt den Fehler EADDRINUSE geben.Gemeinsam Net-Ports mit dem Cluster-Modul

Es scheint nicht der Fall zu sein, dass der Listener nicht korrekt schließt, da ein close -Ereignis ausgegeben wird, wenn ich versuche, den neuen Listener einzurichten. Während dieser Arbeiter EADDRINUSE erhält, können neu hervorgebrachte Arbeiter server.listen() ohne Probleme anrufen.

Hier ist ein einfacher Test, der das Problem demonstrieren wird. Wenn Arbeiter alle 100ms gegabelt werden, stellen sie einen Listener auf Port 16000 her. Wenn Worker 10 gegabelt ist, wird ein Zeitlimit eingerichtet, um seinen Listener nach 1s abzureißen. Sobald ein close Ereignis ausgegeben wird, versucht es, server.listen() erneut auf Port 16000 aufzurufen und den EADDRINUSE Fehler zu erhalten. Aus Konsistenzgründen stellt dieser Test beim Binden explizit die gleiche Adresse bereit, um mögliche Probleme mit Kernmodulen zu vermeiden, die sich mit einer null-Adresse befassen.

Diese spezielle Implementierung führt dazu, dass der Worker 10 dann alle Zyklen aufnimmt, sobald er den Fehler während des Bindens trifft, wodurch der Hauptprozess daran gehindert wird, neue Worker abzuzweigen. Wenn vor dem Aufruf von server.listen() eine Verzögerung hinzugefügt wird, wird Arbeiter 10 weiterhin weiterhin EADDRINUSE erreichen, während der Master ständig neue Worker abgibt, die in der Lage sind, Listener einzurichten.

var cluster = require('cluster'); 
var net  = require('net'); 

if (cluster.isMaster) { 
    setInterval(function(){cluster.fork()},100); 
} else { 
    var workerID = cluster.worker.id; 
    var server; 
    var setup = function() { 
     console.log('Worker ' + workerID + ' setting up listener'); 
     server = net.createServer(function(stream) {}); 
     server.on('error', function(err) { 
      console.log('Error on worker ' + workerID, err); 
      teardown(); 
     }); 
     if (workerID == 10) { 
      server.listen(16000, '127.0.0.1', function() { 
       console.log('Worker ' + workerID + ' listener established'); 
       setTimeout(teardown, 1000); 
      }); 
     } else { 
      server.listen(16000, '127.0.0.1', function() { 
       console.log('Worker ' + workerID + ' listener established'); 
      }); 
     } 
    } 
    var teardown = function() { 
     console.log('Worker ' + workerID + ' closing listener'); 
     server.close(setup); 
    } 
    setup(); 
} 

Anfängliche Ausgabe von diesem Testfall:

Worker 1 setting up listener 
Worker 1 listener established 
Worker 2 setting up listener 
Worker 2 listener established 
Worker 3 setting up listener 
Worker 3 listener established 
Worker 4 setting up listener 
Worker 4 listener established 
Worker 5 setting up listener 
Worker 5 listener established 
Worker 6 setting up listener 
Worker 6 listener established 
Worker 7 setting up listener 
Worker 7 listener established 
Worker 8 setting up listener 
Worker 8 listener established 
Worker 9 setting up listener 
Worker 9 listener established 
Worker 10 setting up listener 
Worker 10 listener established 
Worker 11 setting up listener 
Worker 11 listener established 
Worker 12 setting up listener 
Worker 12 listener established 
Worker 13 setting up listener 
Worker 13 listener established 
Worker 14 setting up listener 
Worker 14 listener established 
Worker 15 setting up listener 
Worker 15 listener established 
Worker 16 setting up listener 
Worker 16 listener established 
Worker 17 setting up listener 
Worker 17 listener established 
Worker 18 setting up listener 
Worker 18 listener established 
Worker 19 setting up listener 
Worker 19 listener established 
Worker 10 closing listener 
Worker 10 setting up listener 
Error on worker 10 { [Error: bind EADDRINUSE 127.0.0.1:16000] 
    code: 'EADDRINUSE', 
    errno: 'EADDRINUSE', 
    syscall: 'bind', 
    address: '127.0.0.1', 
    port: 16000 } 
Worker 10 closing listener 
Worker 10 setting up listener 
Error on worker 10 { [Error: bind EADDRINUSE 127.0.0.1:16000] 
    code: 'EADDRINUSE', 
    errno: 'EADDRINUSE', 
    syscall: 'bind', 
    address: '127.0.0.1', 
    port: 16000 } 
Worker 10 closing listener 
+0

verfügbar Wenn Sie Port 0 statt 16000 hören (was bedeutet, dass der Listening-Port wird zufällig, sondern alle Arbeitnehmer, die gleichen zufälligen Port verwenden werden), um den Fehler wird nicht geworfen, also frage ich mich, ob [dieser Code] (https://github.com/nodejs/node/blob/cee4c25c9281d106f80b20ba7854bf9003f9357a/lib/net.js#L1310-L1315) den Fehler verursacht (obwohl es nicht funktioniert Es macht keinen Sinn, denn AFAICS würde bedeuten, dass es in Häfen keine Übereinstimmung gibt, die es nicht geben sollte. – robertklep

+0

Wenn Port 0 anstelle von 16000 verwendet wird, werden alle ursprünglichen Listener auf demselben Port (in meinem Fall 53230) eingerichtet, aber wenn Worker 10 einen anderen Listener mit Port 0 startet, scheint er den Port zu inkrementieren (53230 für das erste Hören, 53231 für das zweite Hören usw.). –

+0

Ugh, das habe ich nicht bemerkt. Es hört sich an, als würde "server.listen()" in einem Worker ein zweites Mal mit Problemen behaftet sein. – robertklep

Antwort

3

Das Problem erscheint den Clustermodul intern zu sein und über this issue auf dem Knoten Github verfolgt wird.

Problem wurde jetzt aktualisiert und als behoben geschlossen.

Update: Dieses Update ist in V6.2.1

Verwandte Themen