Reputation: 87873
Here is a simple webserver I am working on
var server = require("http").createServer(function(req,resp) {
resp.writeHead(200,{"Content-Type":"text/plain"})
resp.write("hi")
resp.end()
server.close()
})
server.listen(80, 'localhost')
// The shortest webserver you ever did see! Thanks to Node.JS :)
Works great except for keep-alive. When the first request comes in, server.close
gets called. But the process does not end. Actually the TCP connection is still open which allows another request to come through which is what I am trying to avoid.
How can I close existing keep-alive connections?
Upvotes: 32
Views: 25768
Reputation: 8087
How can I close existing keep-alive connections?
Since Node 8.0.0, you can set the server keepAliveTimeout
attribute to 1
millisecond (it is set to 5000
milliseconds by default):
server.keepAliveTimeout
Added in: v8.0.0
<number>
Timeout in milliseconds. Default:5000
(5 seconds).The number of milliseconds of inactivity a server needs to wait for additional incoming data, after it has finished writing the last response, before a socket will be destroyed. If the server receives new data before the keep-alive timeout has fired, it will reset the regular inactivity timeout, i.e.,
server.timeout
.A value of
0
will disable the keep-alive timeout behavior on incoming connections. A value of0
makes the http server behave similarly to Node.js versions prior to 8.0.0, which did not have a keep-alive timeout.The socket timeout logic is set up on connection, so changing this value only affects new connections to the server, not any existing connections.
Alternatively, since Node 18.2.0, you can call the server closeIdleConnections()
method:
server.closeIdleConnections()
Added in: v18.2.0
Closes all connections connected to this server which are not sending a request or waiting for a response.
For instance, this is useful for running a test suite of an HTTP server fast instead of waiting 5 seconds for the default keep-alive timeout:
import assert from 'node:assert/strict';
import http from 'node:http';
import test from 'node:test';
test.describe(() => {
const server = http.createServer((request, response) => {
response.statusCode = 200;
response.setHeader('Content-Type', 'text/plain');
response.setHeader('Content-Length', '12');
response.end('hello, world');
});
server.listen(8000, 'localhost');
test.after(() => {
server.closeIdleConnections();
server.close();
});
test.test(async () => {
const response = await fetch('http://localhost:8000/');
assert.equal(response.status, 200);
assert.equal(response.headers.get('Content-Type'), 'text/plain');
assert.equal(response.headers.get('Content-Length'), '12');
assert.equal(await response.text(), 'hello, world');
});
});
Alternatively, since Node 19.0.0, you can rely on the server close()
method to implicitly call the server closeIdleConnections()
method so the previous suggestions do not apply anymore:
server.close([callback])
History
Version Changes v19.0.0 The method closes idle connections before returning. v0.1.90 Added in: v0.1.90
- callback
<Function>
Stops the server from accepting new connections and closes all connections connected to this server which are not sending a request or waiting for a response. See
net.Server.close()
.
Upvotes: 0
Reputation: 663
If you're closing the server as part of a graceful shutdown of the process, you just need this:
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();
});
}
Basically, the sockets that your server uses will only keep the process alive while they're actually serving a request. While they're just sitting there idly (because of a Keep-Alive connection), a call to server.close()
will close the process, as long as there's nothing else keeping the process alive. If you need to do other things after the server closes, as part of your graceful shutdown, you can hook into process.on('beforeExit', callback)
to finish your graceful shutdown procedures.
Upvotes: 4
Reputation: 801
You can control the idle timeout for a connection, so you can set how long a keep-alive connection will remain open. For example:
server=require('http').createServer(function(req,res) {
//Respond
if(req.url.match(/^\/end.*/)) {
server.close();
res.writeHead(200,{'Content-Type':'text/plain'});
res.end('Closedown');
} else {
res.writeHead(200,{'Content-Type':'text/plain'});
res.end('Hello World!');
}
}).listen(1088);
//Set the idle timeout on any new connection
server.addListener("connection",function(stream) {
stream.setTimeout(4000);
});
We can test this with netcat:
ben@quad-14:~/node$ echo -e "GET /test HTTP/1.1\nConnection: keep-alive\n\n" | netcat -C -q -1 localhost 1088
HTTP/1.1 200 OK
Content-Type: text/plain
Connection: keep-alive
Transfer-Encoding: chunked
c
Hello World!
0
after 4 seconds, the connection closes
And now we can show that closing the server works: after all idle connections are dropped, the server exits:
ben@quad-14:~/node$ echo -e "GET /end HTTP/1.1\nConnection: keep-alive\n\n" | netcat -C -q -1 localhost 1088
HTTP/1.1 200 OK
Content-Type: text/plain
Connection: keep-alive
Transfer-Encoding: chunked
9
Closedown
0
after 4 seconds, the connection closes and the server exits
Upvotes: 23
Reputation: 35263
You can call request.connection.destroy()
in the response callback. That will close the request connection.
It will also end your process since there is nothing left to do, the end result is the same as calling process.exit()
right there.
Upvotes: 19