node.js - run - Cierre bien el servidor de zócalos UNIX en NodeJS que se ejecuta en Forever
pm2 node service (5)
Tengo una aplicación NodeJS que configura un socket UNIX para exponer algún canal de comunicación entre procesos (algún tipo de control). El archivo de socket UNIX se coloca en la carpeta os.tmpdir()
(es decir, /tmp/app-monitor.sock
).
var net = require(''net'');
var server = net.createServer(...);
server.listen(''/tmp/app-monitor.sock'', ...);
Uso un control de señal (SIGINT, SITERM, etc.) para apagar mi servidor y eliminar un archivo de socket.
function shutdown() {
server.close(); // socket file is automatically removed here
process.exit();
}
process.on(''SIGINT'', shutdown);
// and so on
Mi aplicación se está ejecutando forever start ...
para monitorear su ciclo de vida.
Tengo un problema con el comando forever restartall
. Cuando hace siempre restartall
, está utilizando un SIGKILL
para terminar todos los procesos secundarios. SIGKILL
no puede ser manejado por un proceso, por lo que mi aplicación muere sin ningún procedimiento de cierre.
El problema es un archivo de socket que no se elimina cuando se utiliza SIGKILL
. Después de reiniciar el proceso hijo, no se puede iniciar el nuevo servidor porque una llamada de listen
causará un error EADDRINUSE
.
No puedo eliminar un archivo de socket existente durante el inicio de una aplicación porque no sé si es un socket que funciona realmente o algunos rastros de un cierre impuro anterior.
Entonces, la pregunta es ... ¿Cuál es la mejor manera de manejar tal situación (SIGKILL y servidor de socket UNIX)?
Como han mencionado otras personas, no puede hacer nada en respuesta a SIGKILL, que es en general el motivo por el cual, forever
todos (y todos los demás) no utilicen SIGKILL, excepto en circunstancias extremas. Así que lo mejor que puedes hacer es limpiar en otro proceso.
Te sugiero que limpies al comienzo. Cuando obtenga EADDRINUSE
, intente conectarse al zócalo. Si la conexión de socket se realiza correctamente, se está ejecutando otro servidor y, por lo tanto, esta instancia debería salir. Si la conexión falla, es seguro desvincular el archivo de socket y crear uno nuevo.
var fs = require(''fs'');
var net = require(''net'');
var server = net.createServer(function(c) { //''connection'' listener
console.log(''server connected'');
c.on(''end'', function() {
console.log(''server disconnected'');
});
c.write(''hello/r/n'');
c.pipe(c);
});
server.on(''error'', function (e) {
if (e.code == ''EADDRINUSE'') {
var clientSocket = new net.Socket();
clientSocket.on(''error'', function(e) { // handle error trying to talk to server
if (e.code == ''ECONNREFUSED'') { // No other server listening
fs.unlinkSync(''/tmp/app-monitor.sock'');
server.listen(''/tmp/app-monitor.sock'', function() { //''listening'' listener
console.log(''server recovered'');
});
}
});
clientSocket.connect({path: ''/tmp/app-monitor.sock''}, function() {
console.log(''Server running, giving up...'');
process.exit();
});
}
});
server.listen(''/tmp/app-monitor.sock'', function() { //''listening'' listener
console.log(''server bound'');
});
Debería poder utilizar SIGTERM para hacer lo que quiera: process.on(''SIGTERM'', shutdown)
Ya que no puede manejar SIGKILL
y quiere usar para siempre (que usa SIGKILL
) tendrá que usar una solución alternativa.
Por ejemplo, primero envíe una señal para apagar su servidor y luego reinicie para siempre:
kill -s SIGUSR1 $pid
# $pid contains the pid of your node process, or use
# killall -SIGUSR1 node
sleep 2
forever restart test.js
En su js manejar SIGUSR1:
process.on(''SIGUSR1'', gracefullyShutdownMyServer);
debe elegir
- cambie SIGKILL a otra señal en forever-monitor para manejar en la aplicación
- Cuida tu aplicación en este caso, utilizando fs.unlink.
- deja de usar para siempre
server.on(''error'', function (e) {
if (e.code == ''EADDRINUSE'') {
console.log(''Address in use, retrying...'');
setTimeout(function () {
server.close();
server.listen(PORT, HOST);
}, 1000);
}
});
http://nodejs.org/api/net.html#net_server_listen_port_host_backlog_callback
UPD
no puedes manejar SIGKILL, entonces debes limpiar el manual del zócalo
este ejemplo funciona bien para siempre
var fs = require(''fs'');
var net = require(''net'');
var server = net.createServer(function(c) {});
server.listen(''./app-monitor.sock'', function() {
console.log(''server bound'');
});
server.on(''error'', function (e) {
if (e.code == ''EADDRINUSE'') {
console.log(''Address in use, retrying...'');
setTimeout(function () {
fs.unlink(''./app-monitor.sock'');
}, 1000);
}
});