Skip to content

Instantly share code, notes, and snippets.

@miketromba
Created March 31, 2021 20:15
Show Gist options
  • Save miketromba/3f6da61de0da598737860f81c2bdae51 to your computer and use it in GitHub Desktop.
Save miketromba/3f6da61de0da598737860f81c2bdae51 to your computer and use it in GitHub Desktop.
RecurringTask.js
// Utility for running recurring tasks
// Uses setInterval and setTimeout
// Has ability to schedule the first run instantly or wait for a fixed MS
export default class RecurringTask {
constructor({
task, // can be async
intervalMs = 1000, // interval in milliseconds
lastRun = 0, // 0 == run immediately
// mode can be "gap" or "strict" or "hybrid"
// "strict" (overlap) will run every intervalMs religiously, even if that means overlapping with prior tasks that take longer than intervalMs to execute
// "gap" (no overlap, wait) will only schedule the next task for intervalMs AFTER the previous task has concluded. There will never be execution overlap, and the intervalMs gap will always be maintained
// "hybrid" (no overlap, run asap) will act like "strict" mode BUT will never overlap. If a task's execution time exceeds intervalMs, it will wait until that task completes and then immediately begin the next task.
mode = 'gap' // gap is the safest default for most situations
})
{
this.task = task
this.intervalMs = intervalMs
this.lastRun = lastRun
this.mode = mode
}
get timeUntilNextRun(){
return Math.max(this.intervalMs - (Date.now() - this.lastRun), 0)
}
// Schedule the first run
start(){
setTimeout(this.safeRunTask.bind(this), this.timeUntilNextRun)
}
// Runs right before a task is attempted
before(){
if (this.mode == 'strict' || this.mode == 'hybrid')
this.lastRun = Date.now()
if (this.mode == 'strict')
setTimeout(this.safeRunTask.bind(this), this.intervalMs)
}
// Runs right after a task is attempted
after(){
if (this.mode == 'gap'){
this.lastRun = Date.now()
setTimeout(this.safeRunTask.bind(this), this.intervalMs)
}
if (this.mode == 'hybrid')
setTimeout(this.safeRunTask.bind(this), this.timeUntilNextRun)
}
async safeRunTask(){
this.before()
try { await this.task() }
catch (e) { }
this.after()
}
}
// import { sleep } from './sleep'
// test()
// async function test(){
// const task = new RecurringTask({
// intervalMs: 1000,
// lastRun: 0, // Date.now(),
// mode: 'hybrid',
// async task(){
// const ID = Math.round(Math.random() * 10000)
// console.log(`Begin task ${ID}`)
// await sleep(2000)
// console.log(`End task ${ID}`)
// }
// })
// task.start()
// }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment