Corey Ogburn
Corey Ogburn

Reputation: 24717

Node app doesn't terminate after web request?

I'm reading IDs from a text file and making some RESTful requests. It works, but when all IDs have been run, the node app stays running.

main.js:

var fs = require('fs');
var http = require('http');

var ids = fs.readFileSync('test.txt', { encoding: 'utf8' });
ids = ids.split('\n');
var options = {
    hostname: 'internalhost',
    port: 80,
    path: '',
    method: 'DELETE'
};
for (var i = 0; i < ids.length; i++) {
    options.path = '/thing/' + ids[i];
    console.log('Deleting thing ' + ids[i]);

    var req = http.request(options, function(res) {
        console.log('Status: ' + res.statusCode);
    });

    req.on('error', function(e) {
        console.log('Problem with request: ' + e.message);
    });

    req.end();
}

The requests are made successfully but after the last one, the app continues to run. I've tried adding res.end() right after I print the response's status code, but then I get an error that res doesn't have a method end.

What's going on here?

Upvotes: 2

Views: 1066

Answers (2)

josh3736
josh3736

Reputation: 144912

It appears you're suffering from a side-effect of HTTP keep-alives. Node does not exit when there are TCP connections open, and the HTTP Agent leaves TCP connections open for an indefinite amount of time.

You've mentioned that keep-alives will be beneficial for you, so your options are limited.

  • Simply disabling the Agent will result in keep-alives being disabled, so this isn't really an option.

  • You can manually manage and track your requests, and when all have been completed, call process.exit. I don't like this, however, as it is a rather blunt instrument. If you have other async operations running (such as DB calls), you may accidentally end your app before those operations complete.

  • You can manually manage and track your requests. When all have been completed, you can loop through the Agent instance's sockets property and close all lingering sockets. (Warning: calling close on an already closed socket throws.)

    This is a much safer approach because other outstanding operations will be allowed to finish before the app exits.

  • You could upgrade to node ≥ 0.11.4. (Realistically, you'd probably want to wait until 0.12 stable is released.) The next node version has a greatly improved Agent implementation that unrefs idle sockets kept in the Agent's connection pool. In other words, node can exit if the only open TCP connections are those being held for reuse as a keep-alive connection.

  • You could also rip out the new Agent implemention from the unstable branch and use it for your app's requests instead of the default Agent provided by your version of node. (This is probably what I'd do.)

Upvotes: 3

Farid Nouri Neshat
Farid Nouri Neshat

Reputation: 30430

node will only terminate if there are no pending events to be handled. In this case I believe the connection is still open, so you can either destroy it manually by calling res.socket.end() or res.destroy() or as @ExplosionPills Suggested, just call process.exit when all requests are done. You can use async module to help you to achieve this.

Upvotes: 2

Related Questions