Over-thinking #3: Restarting a node.js process

Sure, you could use something like forever but what if you want things as self contained as possible?

It’s very ugly and breaks stdio, but it works!

var cluster = require('cluster');
var _ = require('underscore');
var spawn = require('child_process').spawn;
if(cluster.isMaster) {
  //var cluster_args = 
  var runningragnarok = false;
  var msghandler = function(msg) {
    if(msg === 'rebirth') {
      _.each(cluster.workers, function(v) {
        v.kill();
      });
    }
    if(msg === 'ragnarok' && runningragnarok === false) {
      runningragnarok = true;
      var nargs = process.argv;
      nargs.splice.apply(nargs, [1, 0].concat(process.execArgv));
      if(!_.contains(process.argv, '--regnarok')) {
        nargs.push('--ragnarok');
        nargs.push(5000);
      }
      _.each(cluster.workers, function(w) { w.kill(); });
      spawn(nargs[0], nargs.slice(1), {detached: true, stdio: ['ignore', 'ignore', 'ignore']});
      process.kill(process.pid);
    }

    if(msg === 'heatdeath') {
      process.kill(process.pid);
    }
  };

  cluster.on('exit', function() { if(runningragnarok) return; cluster.fork().on('message', msghandler); });

  setTimeout(function() {
    _.each([1,2,3,4,5], function() {
      var f = cluster.fork()
      f.on('message', msghandler);
    })
  }, 5000);
  //_.find(process.argv, function(v, i, a) { return i > 0 && a[i-1] === '--ragnarok'; }) || 5000
  return;
}

Over-thinking #2: Javascript inheritance

As with all things, I was in need of a solution. The problem was that multiple object prototypes were needing to be mixed together into one. No npm package I found seemed to do the trick for me in the way I wanted and needed things to work. So of course I reinvented the wheel and made multiinherits.

The main reason for this is that I wanted a way to specify what super constructor to call.

Over-thinking #1: Node.js HTTP requests

Something I’ve been toying with is a tip and trick, but mostly horrible hacking away and over-thinking things blog series highlighting the stupid things I do. These things will likely come from stuff for my work or simply curiosity.

Without further ado, here’s #1.

A couple a weeks ago, I needed to migrate a web server and test the sites before going live. Due to a variety of constraints, editing the hosts file, using something like DNShifter or editing the hostname for the vhosts was out of the question. What is a guy to do? Thinking over the problem I figured node.js would be the quickest route to write a testing routine with.

The first problem and probably the biggest was to construct the http request in such a way that I would connect to a different host than the hostname would otherwise send me to. Looking at the node.js code on github made me think it was going to be a piece of cake, just a couple additions to the /lib http files would allow me to specify the actual host to connect with.

//around /lib/http.js:1425
else if(options.connection) {
 self.onSocket(options.connection)
}

This allowed me to use a specific socket made by net.createConnection. However, this is clunky and I’d have to maintain a copy of the mainline http with this and all the other necessary code changes. Obviously this is more work in the long run and my future self is lazy.

Thankfully the folks who wrote the http module decided to check if the options object for http.request() has “createConnection” defined and then uses that to initiate the TCP stream. This makes the task so much easier and should work for the foreseeable future.

var url = require().parse("http://example.com/");
url.createConnection = require('net').createConnection.bind(null, 80, "snoj.us");
require('http').request(url, function(res) {
  res.setEncoding('utf8');
  res.on('data', function (chunk) {
    console.log('BODY: ' + chunk);
  });
}).end();

And of course since drafting all this drivel I find that wget (starting with 1.10), Invoke-WebRequest, and node.js allow the Host header to be specified and each works excellently. However, I still like this technique as it allows you to leave the original URL in place while forcing a connection to another server. Using custom headers means editing the URL which may or may not be doable in some situations and calls for more code changes to accomplish the same end.