2

I'm having an issue with my code below, where my config variable is being updated in some area, but in the function within http.createServer, it isn't changing. I have some comments to indicate what's going on in the code below. My guess is config is being held onto somewhere, or I don't understand JavaScript scope as well as I thought. Can anyone explain what's going on here?

EDIT: it looks like what was happening is the client & server were keeping the socket open because of the Connection: keep-alive header. For the time being (because this is meant to be a local server with low traffic), I've added res.setHeader('Connection','close'); which appears to fix this issue when using the same client to connect in short intervals after a configuration change.

// global variables & configuration
var fs = require('fs');
var utils = require('./utils.js');
var configFile = 'config.json';
var initialConfig = JSON.parse(fs.readFileSync(configFile));
var server = {};

// watch file system for changes to configuration
fs.watchFile(configFile, function(curr, prev) {
    console.log('config change detected');
    // reload the configuration
    var config = JSON.parse(fs.readFileSync(configFile)); // config is correct
    if (typeof server !== 'undefined') {
        server.close();
    }
    serveStatic(config);
});

// start the server
serveStatic(initialConfig);

// server functions
function serveStatic(config) {
    var http = require('http'); // config is the new (correct) value
    var startTime;
    server = http.createServer(function(req, res) { // config is the old value, never changes
        try {
            // solution: res.setHeader('Connection','close');
            res.end(JSON.stringify(config));
        } catch (err) {
            if (res.statusCode === 200)
                res.statusCode = 500;
            res.write(http.STATUS_CODES[res.statusCode]);
            if (config.detailed_errors)
                res.write('\n' + err);
            res.end();
        }
    });
    console.log('Starting server on port ' + config.port);
    server.listen(config.port);
}
Nathan
  • 2,093
  • 3
  • 20
  • 33

1 Answers1

1

Your problem is with server.close. Check this question and this one

server.close()

However, this only prevents the server from receiving any new http connections. It does not close any that are still open. http.close() takes a callback, and that callback does not get executed until all open connections have actually disconnected. Is there a way to force close everything?

What is happening is you might be creating multiple servers as the connections have not been disconnected yet. I don't think the variable is not changing. I have tested your code and there are multiple servers being created(on different ports ofcourse) when the file is changed. So your real problem is to gracefully shut down the http server immediately which is answered in the questions linked.

Community
  • 1
  • 1
ma08
  • 3,654
  • 3
  • 23
  • 36
  • I tried adding `server = null;` after the `server.close()` to make sure the new server wouldn't have any issues. Even if the old server was still floating around in memory somewhere, why would it cause the new server to use the old configuration? – Nathan Aug 02 '14 at 20:04
  • Are you sure that the server is using the old configurations. Maybe the tests you are using involve some unusable ports. You can't create a server over every other port as some ports are already in use. So make intelligent tests. For ex. 3000 followed by 5000 and 5001 works for me and come to a conclusion. And the old servers started are indeed closing over some time(after closing their connections) – ma08 Aug 02 '14 at 20:16
  • 1
    The code works when re-using the same port every time, another indication that there aren't multiple servers running. I think scoping is the issue. I think somehow the original config is being closured into the callback passed to http.createServer, and it just won't change for some reason. – anderspitman Aug 02 '14 at 20:20
  • @anders Strange. For me there are multiple servers when testing most of the times. – ma08 Aug 02 '14 at 20:21
  • I tried switching my config from port 8080 to port 8000, and console logged port 8080 for both inside `http.createServer`. However, I tried hitting the server from an incognito window after the first restart, and it received the updated config. It looks like it is an issue with keep-alive and the same client being served from the same socket. I'm guessing the sockets it hands out aren't necessarily on the same port as the original request. – Nathan Aug 02 '14 at 20:21
  • @Nathan console logged 8080 after changing? For me the log works perfectly whenever I change the config. Something weird going on. – ma08 Aug 02 '14 at 20:25
  • It would log 8080 after changing the config because that same client was still tied to the original socket, and using the old configuration. – Nathan Aug 02 '14 at 20:29
  • I agree with @anders, this issue is entirely scoping. Multiple servers are not running. – SamT Aug 02 '14 at 20:29
  • @Nathan can you tell us what conclusion you have come to? – ma08 Aug 02 '14 at 20:30
  • It definitely looks like multiple servers. I'd be happy to hop onto a chat with you guys so we can discuss it without flooding the comments. – Nathan Aug 02 '14 at 20:34
  • Do you have a solution? If not could you unaccept the answer so maybe someone with the right knowledge will come along and enlighten us? – anderspitman Aug 02 '14 at 20:46
  • I have a solution, which was to set the Connection header to `close`. Take a look at the edit in my original post. – Nathan Aug 02 '14 at 20:48
  • @Nathan Cool. You can also try the solution in the second link in my answer(if it doesn't seem overkill) while keeping the connection type keep-alive. – ma08 Aug 02 '14 at 20:51
  • It is overkill for this project. It's a local development server for serving static files, so the performance hit from not using keep-alive is a non-issue. – Nathan Aug 02 '14 at 21:09