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

Как закрыть сервер Node.js http (s) немедленно?

У меня есть приложение Node.js, которое содержит HTTP-сервер.

В конкретном случае мне нужно программно завершить работу этого сервера. То, что я сейчас делаю, вызывает функцию close(), но это не помогает, так как он ожидает, что все поддерживаемые живые соединения будут завершены в первую очередь.

Итак, в основном, это завершает работу сервера, но только после минимального времени ожидания 120 секунд. Но я хочу, чтобы сервер немедленно отключился - даже если это означает разрыв с обработанными в настоящее время запросами.

То, что я не могу сделать, это просто

process.exit();

поскольку сервер является только частью приложения, а остальная часть приложения должна работать. Я ищу концептуально нечто вроде server.destroy(); или что-то в этом роде.

Как я мог достичь этого?

PS: обычно требуется время ожидания подключения для соединений, поэтому на этот раз это не является жизнеспособным вариантом.

4b9b3361

Ответ 1

Фокус в том, что вам нужно подписаться на сервер connection событие, которое дает вам сокет нового соединения. Вам нужно запомнить этот сокет, а затем, сразу после вызова server.close(), уничтожить этот сокет с помощью socket.destroy().

Кроме того, вам нужно прослушать событие socket close, чтобы удалить его из массива, если он естественным образом покидает его, потому что его тайм-аут сохранения продолжается.

Я написал небольшое примерное приложение, которое вы можете использовать, чтобы продемонстрировать это поведение:

// Create a new server on port 4000
var http = require('http');
var server = http.createServer(function (req, res) {
  res.end('Hello world!');
}).listen(4000);

// Maintain a hash of all connected sockets
var sockets = {}, nextSocketId = 0;
server.on('connection', function (socket) {
  // Add a newly connected socket
  var socketId = nextSocketId++;
  sockets[socketId] = socket;
  console.log('socket', socketId, 'opened');

  // Remove the socket when it closes
  socket.on('close', function () {
    console.log('socket', socketId, 'closed');
    delete sockets[socketId];
  });

  // Extend socket lifetime for demo purposes
  socket.setTimeout(4000);
});

// Count down from 10 seconds
(function countDown (counter) {
  console.log(counter);
  if (counter > 0)
    return setTimeout(countDown, 1000, counter - 1);

  // Close the server
  server.close(function () { console.log('Server closed!'); });
  // Destroy all open sockets
  for (var socketId in sockets) {
    console.log('socket', socketId, 'destroyed');
    sockets[socketId].destroy();
  }
})(10);

В основном, он запускает новый HTTP-сервер, рассчитывает от 10 до 0 и закрывает сервер через 10 секунд. Если соединение не установлено, сервер немедленно отключается.

Если соединение установлено и оно все еще открыто, оно уничтожается. Если он уже умер естественным образом, в этот момент распечатывается только сообщение.

Ответ 2

Я нашел способ сделать это, не отслеживая подключения или не закрывая их. Я не уверен, насколько это надежна в версиях Node или если есть какие-то негативные последствия для этого, но, похоже, он отлично работает для того, что я делаю. Хитрость заключается в том, чтобы выпустить событие "закрыть", используя setImmediate сразу после вызова метода close. Это работает так:

server.close(callback);
setImmediate(function(){server.emit('close')});

По крайней мере, для меня это освобождает порт, чтобы я мог запустить новую службу HTTP (S) к моменту вызова callback (что очень много мгновенно). Существующие соединения остаются открытыми. Я использую это для автоматического перезапуска службы HTTPS после обновления сертификата Let Encrypt.

Ответ 3

Если вам нужно сохранить процесс в живых после закрытия сервера, то решение Golo Roden, вероятно, лучше всего.

Но если вы закрываете сервер как часть изящного завершения процесса, вам просто нужно:

var server = require('http').createServer(myFancyServerLogic);

server.on('connection', function (socket) {socket.unref();});
server.listen(80);

function myFancyServerLogic(req, res) {
    req.connection.ref();

    res.end('Hello World!', function () {
        req.connection.unref();
    });
}

В принципе, сокеты, используемые вашим сервером, будут поддерживать этот процесс только в том случае, если они фактически выполняют запрос. Хотя они просто сидят там без дела (из-за подключения Keep-Alive), вызов server.close() закроет процесс, пока ничего не останется в живых. Если вам нужно делать другие вещи после закрытия сервера, как часть вашего изящного отключения, вы можете подключиться к process.on('beforeExit', callback), чтобы закончить свои изящные процедуры выключения.

Ответ 4

Библиотека https://github.com/isaacs/server-destroy обеспечивает простой способ destroy() сервера с поведением, желательным в вопросе (путем отслеживания открытых соединений и уничтожая каждый из них на сервере, уничтожая, как описано в других ответах).

Ответ 5

Как говорили другие, решение состоит в том, чтобы отслеживать все открытые сокеты и закрывать их вручную. Мой node пакет killable может сделать это за вас. Пример (используя экспресс, но вы можете использовать killable для любого экземпляра http.server):

var killable = require('killable');

var app = require('express')();
var server;

app.route('/', function (req, res, next) {
  res.send('Server is going down NOW!');

  server.kill(function () {
    //the server is down when this is called. That won't take long.
  });
});

var server = app.listen(8080);
killable(server);

Ответ 6

Еще один пакет nodejs для выполнения отключений, связанных с отключением: http-shutdown, который, по-видимому, поддерживается на момент написания статьи (сентябрь 2016 г.) ) и работал у меня на NodeJS 6.x

Из документации

Использование

В настоящее время существует две возможности использования этой библиотеки. Первый - это явная упаковка объекта Server:

// Create the http server
var server = require('http').createServer(function(req, res) {
  res.end('Good job!');
});

// Wrap the server object with additional functionality.
// This should be done immediately after server construction, or before you start listening.
// Additional functionailiy needs to be added for http server events to properly shutdown.
server = require('http-shutdown')(server);

// Listen on a port and start taking requests.
server.listen(3000);

// Sometime later... shutdown the server.
server.shutdown(function() {
  console.log('Everything is cleanly shutdown.');
});

Второй неявно добавляет функциональность прототипа к объекту Server:

// .extend adds a .withShutdown prototype method to the Server object
require('http-shutdown').extend();

var server = require('http').createServer(function(req, res) {
  res.end('God job!');
}).withShutdown(); // <-- Easy to chain. Returns the Server object

// Sometime later, shutdown the server.
server.shutdown(function() {
  console.log('Everything is cleanly shutdown.');
});

Ответ 7

Лучше всего было бы убить соединения вручную (т.е. принудительно закрыть его сокеты).

В идеале это должно быть сделано путем копания в внутренности сервера и закрытия его сокетов вручную. В качестве альтернативы можно запустить команду оболочки, которая делает то же самое (при условии, что у сервера есть соответствующие привилегии и c.)

Ответ 8

const Koa = require('koa')
const app = new Koa()

let keepAlive = true
app.use(async (ctx) => {
  let url = ctx.request.url

  // destroy socket
  if (keepAlive === false) {
    ctx.response.set('Connection', 'close')
  }
  switch (url) {
    case '/restart':
      ctx.body = 'success'
      process.send('restart')
      break;
    default:
      ctx.body = 'world-----' + Date.now()
  }
})
const server = app.listen(9011)

process.on('message', (data, sendHandle) => {
  if (data == 'stop') {
    keepAlive = false
    server.close();
  }
})

Ответ 9

process.exit(код);//код 0 для успеха и 1 для отказа