Search code examples
sails.jspm2sails-mongo

sails lowers without process.exit - feature or mistake?


My sails.js app is running under PM2, and I'd like PM2 to be able to restart the app, which it does in the case of a crash. The thing is, when sails fails to load a hook, for instance, if a DB is not available at startup, then the graceful sails.lower() is called internally by sails, but the actual node process does not exit (no process.exit() is called after the lowering) by the core sails code. This has the result of PM2 not knowing that sails has shutdown, and therefore not starting it back up again.

This all happens in the initial bootstrapping of the app, and is before any of my code is called, so I have no control over it.

Does anybody have any suggestions of how I may solve this?

I'm thinking I could write a custom core hook that could hook into the sail.on('lowered', fn) and call a process.exit() on receiving that event. Ideas?

Many thanks.


Solution

  • Sails doesn't call process.exit when it lowers because the Sails app might have been started programmatically (via sails.lift() or sails.lower()), and exiting the process in this way would quit the script that called Sails as well.

    The fact is that Node scripts are supposed to exit automatically when there's nothing left in the event loop. You can verify this yourself by creating a new Sails app with sails new, and creating a test script in that directory like:

    /* testscript.js */
    var Sails = require('sails');
    Sails.load({hooks: {grunt: false, views: false}}, function(err) {
        console.log('lifted sails!');
        Sails.lower(function(err) {
           console.log('lowered sails!');
        });
    });
    

    Do node testscript.js on the command line and you'll see the two logs, and then the command prompt again.

    All this is to demonstrate that if your app is not lowering, it's because something is keeping it from doing so. The most likely thing would be the database adapter. Some adapters (like Postgres) keep TCP connections alive for awhile. If you wait 30 seconds or so you'll likely see the process exit automatically. If 30 seconds is too long to wait, and if you're not calling Sails programmatically, you can certainly call process.exit yourself. You can wait for the lower event, and then give Sails a bit of time to clean up first:

    sails.on('lower', function() { 
       // Give Sails five seconds to shut down before pulling the plug.
       setTimeout(
          function() { process.exit(1); },
          5000
       );
    });
    

    Put that in your config/bootstrap.js and you should be good to go.

    If you want to find out what's actually hanging your process and preventing it from exiting right now, try the excellent why-is-node-running module.

    Note: at the time of this posting, the lower event is incorrectly documented on Sailsjs.com as lowered. This will be fixed ASAP.