0

I'm trying to schedule out social media posts for up to 6 months in advance. I'm using node-cron, which was inspired by gnu cron. I set a script to run every second to log 'tick!' for testing. However if this nodeJS service restarts or goes down the job is lost.

I thought node-cron affected Crontab, but Crontab -l returns no crontab for kevindanikowski.

Is there a different (better) way I should schedule jobs months in advance?

Or is there something about node-cron I'm missing to make sure I don't lose the cronjob?

Kevin Danikowski
  • 4,620
  • 6
  • 41
  • 75
  • 1
    `node-cron` doesn't use gnu cron, it's only *inspired* by it (same pattern syntax for scheduling). – Sven Jun 13 '18 at 01:14
  • Oh, sorry I misread, I will fix that, any idea on the answer to the questions above? – Kevin Danikowski Jun 13 '18 at 01:54
  • 1
    Asking for libraries is off-topic on SO. But you can try Agenda. It uses Mongo for persistence. – Estus Flask Jun 13 '18 at 01:56
  • What's wrong with the actual cron? It doesn't have one second accuracy? – OneCricketeer Jun 13 '18 at 01:57
  • No nothing is wrong with the cron, I'm just not sure how to keep the job when the nodeJS service gets restarted, and thank you @estus, that answers one of the questions, I should be scheduling these in a database for persistence and not rely on crontab perhaps – Kevin Danikowski Jun 13 '18 at 01:58
  • Can you change the title to "How to set up 6 month timer in node.js"?. Then can you post the code you tested - it's OK if the code uses node-cron – slebetman Jun 13 '18 at 01:59
  • I've done this before in several languages and the trick is fairly simple. So I have the answer, just that my answer is not about node-cron – slebetman Jun 13 '18 at 02:00
  • @slebetman, I will accept it if it helps me understand conceptually how it needs to be done – Kevin Danikowski Jun 13 '18 at 02:00

1 Answers1

1

For really long term timers you need to store the timeout data on disk somehow. As you mentioned, if you do it purely in memory you will lose timing information if the server restarts.

The way to handle this is simple. It's the same algorithm cron uses:

  1. Record when you want the timeout to occur on disk - the format is up to you, you may use the cron format or invent your own. Since it's javascript I'd be tempted to simply record in in JSON format.

  2. Read the timing file into your program. There are two ways you can do this. If you are concerned about run-time performance then read it once when your program starts. However this means you need to restart your server if you edit the file. If you want updates to the file to be picked up automatically then read it every time you want to process timing events.

  3. Run a timer loop periodically. Cron for example has a resolution of one minute. Therefore cron runs a timer loop every one minute. If that's good enough than run every one minute. For me I'd do a setInterval() every 30 seconds or so. Note that running an timer loop every second isn't that heavy in javascript on any decent processor.

  4. Process the timer events from the file in the timer loop. Loop through all events and check to see if they have expired.

That's it. This is how all scheduling systems work (google calendar, cron etc.).

Here's a very simple javascript implementation:

var events = require("events.js");

// Assume events.js look something like:
// return [ {
//    timeout: <millisecs like what Date.now() returns>,
//    callback: <function>
// } ]

setInterval(function(){
    var now = Date.now();
    events.forEach(e=>{
        if (e.timeout >= now) {
            e.callback(); // execute event
        }
    });
    events = events.filter(e=>e.timeout<now); // remove stale events
},10000); // every 10 seconds

You can add fancy features like saving current events to disk if there are any changes to it from the code, make the timeout format human readable for debugging, define a system to pass arguments to event callback etc. But the core is very simple.

slebetman
  • 109,858
  • 19
  • 140
  • 171
  • 1
    You will have to figure out how to store functions because functions are not JSON serializable. I cheated a bit by simply requiring a js file. But that's another issue that probably already have answers on SO – slebetman Jun 13 '18 at 02:22