toad-scheduler: Scheduling breaks completely on long intervals
I stumbled upon toad-scheduler while looking for an improved alternative to the native setInterval and I’m liking the simplicity of this project, great job on that aspect.
However this library doesn’t fix a crucial core problem of vanilla Timers: The timeout length must fit into a signed 32-bit integer. It’s a quite frankly pretty unnecessary limit of NodeJS and most browsers, you can not set a timeout for longer than
2 ^ 31 - 1 = 2 147 483 647
milliseconds. Now that seems like a lot but take this example:
const { ToadScheduler, SimpleIntervalJob, Task } = require('toad-scheduler')
const scheduler = new ToadScheduler()
let myTask = new Task('someString', () => { console.log("I've waited a long time for this") })
let myJob = new SimpleIntervalJob({ hours: 720, }, myTask) // or { days: 30, }
scheduler.addSimpleIntervalJob(myJob)
The goal of this code would be executing the Task every 30 days, which is a reasonable interval time for server sided applications in my opinion. However this will instantly break with this warning:
(node:4229) TimeoutOverflowWarning: 2592000000 does not fit into a 32-bit signed integer. Timeout duration was set to 1.
That’s because neither setTimeout or setInterval can handle anything bigger than 24.85 days of a timeout. Now since this module also uses these functions without modification, the same limits apply and the timeout gets set to 1ms right after the warning, meaning your console will be spammed into oblivion when running this.
Now I realize this scheduler is more focused on shorter, more repetitive tasks but I still think this is a fix-worthy issue. Especially because this shouldn’t be extremely hard to fix once you understand where this limit applies.
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Reactions: 3
- Comments: 47 (45 by maintainers)
@fweb-dev I’ve made the library throw an error in such case in 1.4.0 to reduce the amount of surprise, but it would be great to have a proper fix. I don’t think I’ll have time to implement it myself in the nearby future, though.
btw, another interesting thing about using
setInterval: https://stackoverflow.com/questions/8173580/setinterval-timing-slowly-drifts-away-from-staying-accurate Not sure if it actually matters in majority of cases, but worth keeping in mind. Probably a more accurate auto-compensating engine should be created in the future.I think I need to Fork and play around with the tool to see how the task/job mechanism works better.
I appreciate you letting me try to fix this. My prof says it’s a cool bug to work on haha.
@AndreWillomitzer Create a task which knows that we need to do 4 hops. Create job that triggers in 100 ms. Task fires, sees there are hops to be done, creates another task with 3 hops, creates another job, we keep going. Ideally we shouldn’t use any external setIntervals, just rely on existing job/task mechanism.
Thanks that helps! In which constructor are you referring to for calling “new SimpleIntervalJob()”? I’m also a little confused about how to tell if the schedule is exceeding the limit.
A job constructor receives schedule and task. Schedule has “toMSecs()” method which you use to check how many miliseconds to set the job interval execution to right? So as we said before, I can check if “time” variable is greater than 28 days, if it is, I should… call the “new SimpleIntervalJob()” inside where exactly?
Sorry haha this is my first attempt at actually contributing so I want to understand and ask a lot of questions first 😃
Well, I see what the issue is… could you give an example of creating interim tasks?
I know that we need to compare the current time, with the time they want to execute the task and if it’s 0 then it’s time.
But given that I’m new (as of this morning) to this project, could you provide an example of creating a “higher-level-job” to manage something?
I appreciate you talking to me about this by the way!