Dynamic schedule management

@Andrei, could you send me your example flow?

P.S.

When I create a new cronJob using cron.js I still don't get a timerId. For now I'm sticking with the same solution generating a uuid for each job I create.

Hi @scotie, indeed you won't get an explicit timerID. The timer you create is ultimately an object (created by an object constructor). You want to store this object in the flow context to later on to start and stop it using the methods object.start() and object.stop(). Hopefully, the attached flows will help you to understand. Additional remarks: Note that when you create the timer it is initiated on the state "stopped". You need to invoke the method start() to change the status to "running". You can not start a timer scheduled to a past time. If you try to do so you will see a warning message in the debug panel.

[{"id":"35ab147a.f6df6c","type":"tab","label":"CRON.JS","disabled":false,"info":""},{"id":"69aa3983.7a9808","type":"debug","z":"35ab147a.f6df6c","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":590,"y":100,"wires":[]},{"id":"9ab55936.931468","type":"inject","z":"35ab147a.f6df6c","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":180,"y":100,"wires":[["880c30cb.3ed0c"]]},{"id":"880c30cb.3ed0c","type":"function","z":"35ab147a.f6df6c","name":"schedule now +1 minute","func":"var Tron = global.get('cron');\n\nmsg.payload = new Date(msg.payload + 60000);\n\nlet t1 = new Tron.CronJob(msg.payload, \n() => {node.send({\"payload\" : \"Triggering MQTT\"})},\n() => {node.send({\"payload\" : \"Stopped by manual intervention\"})},\nfalse,null,null,false);\n\nglobal.set(\"t1-cron\", t1);\n\nnode.status({text: t1.nextDates(3)});\nmsg.running = t1.running ? \"running\" : \"stopped\";\n\nreturn msg;","outputs":1,"noerr":0,"x":390,"y":100,"wires":[["69aa3983.7a9808"]]},{"id":"5a08b60d.35af78","type":"inject","z":"35ab147a.f6df6c","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":180,"y":400,"wires":[["23b0a72f.efe058"]]},{"id":"23b0a72f.efe058","type":"function","z":"35ab147a.f6df6c","name":"nextDates","func":"let pay = global.get(\"t1-cron\");\n\nif (pay) {\n    msg.payload = pay.nextDates(3);\n    msg.running = pay.running ? \"running\" : \"stopped\";\n    } else {\n        msg.payload =\"not scheduled\";\n        \n    }\n\nnode.status({text: msg.payload});\nreturn msg;","outputs":1,"noerr":0,"x":340,"y":400,"wires":[["f86a3368.28b98"]]},{"id":"72f38e9.e13d17","type":"debug","z":"35ab147a.f6df6c","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":510,"y":340,"wires":[]},{"id":"899679bd.1c5f48","type":"inject","z":"35ab147a.f6df6c","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":180,"y":340,"wires":[["31844f7f.490e5"]]},{"id":"31844f7f.490e5","type":"function","z":"35ab147a.f6df6c","name":"lastDate","func":"pay = global.get(\"t1-cron\");\n\nif (pay) {\n    msg.payload = pay.lastDate();\n    msg.running = pay.running ? \"running\" : \"stopped\";\n} else {\n    msg.payload =\"not scheduled\";\n}\n\nnode.status({text: msg.payload});\n\nreturn msg;\n\n","outputs":1,"noerr":0,"x":360,"y":340,"wires":[["72f38e9.e13d17"]]},{"id":"f86a3368.28b98","type":"debug","z":"35ab147a.f6df6c","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":510,"y":400,"wires":[]},{"id":"777e2247.9ff61c","type":"inject","z":"35ab147a.f6df6c","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":180,"y":160,"wires":[["d04fccfc.b507e"]]},{"id":"d04fccfc.b507e","type":"function","z":"35ab147a.f6df6c","name":"start()","func":"pay = global.get(\"t1-cron\");\n\nif (pay) {\n    pay.start();\n    msg.payload = pay.nextDates(3);\n    msg.running = pay.running ? \"running\" : \"stopped\";\n    node.status({text: msg.running});\n} else {\n    msg.payload =\"not scheduled\";\n}\n\nreturn msg;","outputs":1,"noerr":0,"x":330,"y":160,"wires":[["f64990a2.fa11d"]]},{"id":"f64990a2.fa11d","type":"debug","z":"35ab147a.f6df6c","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":510,"y":160,"wires":[]},{"id":"b1d5632f.f4833","type":"inject","z":"35ab147a.f6df6c","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":180,"y":220,"wires":[["56ca6623.56a228"]]},{"id":"56ca6623.56a228","type":"function","z":"35ab147a.f6df6c","name":"stop()","func":"pay = global.get(\"t1-cron\");\n\nif (pay) {\n    pay.stop();\n    msg.payload = pay.nextDates(3);\n    msg.running = pay.running ? \"running\" : \"stopped\";\n    node.status({text: msg.running});\n} else {\n    msg.payload =\"not scheduled\";\n}\n\nreturn msg;","outputs":1,"noerr":0,"x":330,"y":220,"wires":[["2fa84592.3ebdba"]]},{"id":"2fa84592.3ebdba","type":"debug","z":"35ab147a.f6df6c","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":510,"y":220,"wires":[]},{"id":"25f110ba.002e5","type":"inject","z":"35ab147a.f6df6c","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":180,"y":280,"wires":[["efb44dcb.ea873"]]},{"id":"efb44dcb.ea873","type":"function","z":"35ab147a.f6df6c","name":"is running ?","func":"pay = global.get(\"t1-cron\");\n\ntry {\nif (pay) {\n\n    msg.payload = pay.nextDates(3);\n    msg.running = pay.running ? \"running\" : \"stopped\";\n    node.status({text: msg.running});\n} else {\n    msg.payload =\"not scheduled\";\n    \n}\n}\n\ncatch(err){\n    node.status({});\n    node.warn(\"WARNING: Date in past\");\n}\n\nreturn msg;","outputs":1,"noerr":0,"x":350,"y":280,"wires":[["69bd3948.864518"]]},{"id":"69bd3948.864518","type":"debug","z":"35ab147a.f6df6c","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":510,"y":280,"wires":[]}]

Edit: this is how the library was configured in settings.js

    functionGlobalContext: {
        
        jsonata:require('jsonata'),
        moment:require('moment'),
        chance:require('chance'),
        cron:require('cron'),
1 Like

Thanks a lot @Andrei!

You actually gave me a good idea for something else :slight_smile:

I needed to handle a reboot somehow, so I'm using the JSONata to extract all of my timers from JSON file, split them into array and send to the microservice ( yes, I'm still doing it in a microservice like Julian @TotallyInformation had proposed ) to reinitialize all the timers.

1 Like