Search code examples
node.jsherokujobs

Exit custom function with loop process on node.js shutdown signal


I have a job that is executed ones per day. My app is running on Heroku, and dyno is restarted ones a day.

So what can happen is that during job execution Heroku starts the restart of dyno.

That itself is not a problem as I can start job two times per day, but what is a problem is to stop the job in the middle of task when it is not in stable status.

I would like now somehow to send this signal to job function so I can break any loops and stop function execution in safe way.

I know how to get signal:

process
   .on('SIGTERM', shutdown('SIGTERM'))
   .on('SIGINT', shutdown('SIGINT'))
   .on('uncaughtException', shutdown('uncaughtException'));

function shutdown(signal) {
    console.log(`${ signal }...`);

    return (err) => {
       if (err) console.error(err.stack || err);
       setTimeout(() => {
           console.log('...waited 5s, exiting.');
           process.exit(err ? 1 : 0);
       }, 5000).unref();
    };
}

but how to send this signal to my job function and to break from it safely?

Thank you.


Solution

  • So the best solution I came up with is following.

    // Manage signals
    let shutDownSignal = false;
    
    process
      .on('SIGTERM', shutdown('SIGTERM'))
      .on('SIGINT', shutdown('SIGINT'))
      .on('uncaughtException', shutdown('uncaughtException'));
    
    function shutdown(signal) {
        return (err) => {
            shutDownSignal = true;
            console.log(`Received signal: ${ signal }...`);
            if (err) console.error(err.stack || err);
            setTimeout(() => {
                console.log('...waited 15s, exiting.');
                process.exit(err ? 1 : 0);
            }, 15000).unref();
        };
    }
    
    module.exports.getShutDownSingnal = function(){ return shutDownSignal; }
    

    then with getShutDownSingnal() anywhere I can check whether shutdown is initiated.

    One more thing. It is necessary to put Procfile in app root with

    web: node index.js
    

    in it (or app.js depending what are you using).

    This is necessary so that SIGTERM and SIGKILL signals are transferred correctly to node (for example if using npm, it will not transfer this signal correctly). More about this on Heroku docs

    Maybe this will be useful for someone.