Po uruchomieniu aplikacji node app.js
proces ma tylko jeden wątek. Im dłużej trwa, tym więcej wątków jest tworzonych dla tego procesu. Problem polega na tym, że gdy chcę wykonać specyficzny rodzaj kodu tak:node.js wymusza tylko jeden wątek, aby wykonać kod
var io = require('socket.io')(process.env.PORT);
To nie dlatego, że sygnał został wysłany z wielu wątków i dlatego kod isnt pomyślnie wykonana.
prosty test, jeśli ktoś to zrobić:
var io = require('socket.io')(9001);
var io = require('socket.io')(9002);
var io = require('socket.io')(9003);
var io = require('socket.io')(9004);
to działa dobrze, ale ten kod:
var cPort = 9001;
setInterval(function() {
var io = require('socket.io')(cPort);
cPort++;
}, 1000 * 60 * 2); // 1 sec * 60 seconds * 2 = 2 minutes interval
przyzwyczajenie być wykonywane, ponieważ po 2 minutach węzeł będzie mieć wiele wątków i wszyscy spróbuj wykonać kod - w rezultacie zobaczysz error: address in use
.
Tak więc pomimo uruchamiania wielowątkowego procesu tego samego pliku, jak mogę zmusić węzeł do wykonania tego kodu tylko raz?
06.11.2017 EDIT ----
W celu wyjaśnienia problemu:
co mi chodzi w pytaniu, nie mam problemu z zasobów, jeśli zacznę wszystkich serwerów na raz (na przykład 40 serwerów) wszystkie są uruchamiane pomyślnie i działają bezterminowo. Problem może się pojawić, jeśli uruchomię tylko jeden serwer, a następnie uruchomę kod, który automatycznie uruchamia się w razie potrzeby. W tym momencie zawsze widzę błąd address in use
, oczywiście adres nie jest używany w momencie wykonania kodu. Obecnie muszę ręcznie uruchamiać więcej serwerów w weekendy, kiedy w innych dniach tygodnia jest więcej osób korzystających z usług i mniej serwerów, chciałem stworzyć zautomatyzowany system, który uruchamia i zamyka serwery w oparciu o populację.
jest to kod serwerów rozruchu:
var cp = require('child_process'),
servers = [],
per_server = config.per_server,
check_servers = function(callback) {
for(var i = 0; i < servers.length; i++) {
callback(i, servers[i]);
}
};
this.add_server = function(port) {
var server = {
port: port,
load: 0,
process: cp.fork(__dirname + '/../server_instance.js', [], {
env: {
port: port
}
})
};
server.process.on('message', function(message) {
server.load = message.load;
});
servers.push(server);
};
this.find_server = function() {
var min = Infinity,
port = false;
check_servers(function(index, details) {
if(details.load < min) {
min = details.load;
port = details.port;
}
});
return port;
};
teraz gdybym wykonać controller.add_server()
40 razy w wierszu rozpocznie 40 serwerów poprawnie, ale jeśli mogę to zrobić:
var start_port = 3185;
setInterval(function() {
var min = Infinity;
check_servers(function(index, details) {
if(details.load < min) {
min = details.load;
}
});
if(min > config.per_server) {
controller.add_server(start_port);
start_port++;
}
}, 5000);
otrzymuję losowy błąd podczas tworzenia drugiego, trzeciego i czwartego serwera, którego adres jest już używany.
07.11.2017 EDIT ----
Jak sugeruje Próbowałem następujących bibliotek do skanowania portów/Finder:
Tylko używając Pierwszy z nich był w stanie uruchomić co najmniej 2 serwery, jest to kod, którego użyłem:
setInterval(function() {
var min = Infinity;
check_servers(function(index, details) {
if(details.load < min) {
min = details.load;
}
});
if(min > per_server) {
_self.add_server();
}
}, 5000);
var portfinder = require('portfinder');
portfinder.basePort = 3185;
this.add_server = function() {
portfinder.getPortPromise()
.then((port) => {
console.log('port found', port);
var server = {
port: port,
load: 0,
process: cp.fork(__dirname + '/../server_instance.js', [], {
env: {
port: port
}
})
};
server.process.on('message', function(message) {
server.load = message.load;
});
servers.push(server);
})
.catch((err) => {
console.log('error happened');
});
};
Po wielu testach wygląda na to, że mogę uruchomić 2 serwery, a następnie losowo, przy trzeciej lub czwartej próbie. Jest jasne, że problem jest głębszy niż w przypadku znalezienia portów, ta biblioteka mówi mi tylko to, co już wiem, wiem, które porty są otwierane, i dwukrotnie sprawdzam, czy przed uruchomieniem skryptu spróbuję uruchomić serwer za pomocą polecenia ręcznego netstat -anp | grep PORT
.
Jasne, że problem nie polega na wyszukiwaniu otwartych portów, z punktu widzenia wyniku wygląda na to, że węzeł próbuje uruchomić serwer wiele razy z pojedynczego polecenia.
śledzić EDIT ----
dodanie server_instance.js Kod:
var io = require('socket.io')(process.env.port),
connections_current = 0,
connections_made = 0,
connections_dropped = 0;
io.on('connection', function(socket) {
connections_current++;
connections_made++;
// ... service logic here, not relevant (like query db, send data to users etc)
socket.on('disconnect', function() {
connections_current--;
connections_dropped++;
});
});
setInterval(function() {
process.send({
load: connections_current
});
}, 5000);
08.11.2017 EDIT ----
byłem testując wiele rozwiązań rozwiązać problem i zaobserwowałem tę sytuację:
test lokalny na mac osx, w którym mogę wygenerować maksymalnie 3000 połączeń z serwerem. Błąd nigdy się nie zdarza, węzeł ma
1 process
i6 threads
dla pliku routera. Dzięki 3000 połączeń mogę bez problemu wygenerować nawet 200 serwerów.test serwera na debiunie linux, gdzie generuję 2 miliony połączeń z serwerem. Błąd zawsze dzieje się na 3. lub 4. instancji serwera, gdy łączę wszystkie węzły osób ma
6 processes
i10 threads for every process
dla pliku routera.
To jest oczywiście źródło problemu, im więcej mam pojemności, tym więcej spawnuje się węzłów procesów i wcześniej będzie się nakładać podczas próby uruchomienia nowego serwera.
Nie jest jasne, co próbujesz osiągnąć. Twój kod 'setInterval()' uruchamia się w nieskończoność, uruchamiając coraz więcej serwerów, aż do wyczerpania zasobów po stronie serwera. – jfriend00
@ jfriend00 https://stackoverflow.com/questions/47071894/socket-io-dynamically-start-servers-to-listen może rzucić trochę światła –
Co to oznacza 'Nie działa, ponieważ sygnał został wysłany z wielu wątków, a zatem kod isnt pomyślnie wykonany.? – jfriend00