Files

56 lines
1.6 KiB
JavaScript

export class UpdateScheduler {
constructor({
check,
intervalSeconds = 21_600,
onError = async () => {},
random = Math.random,
setTimer = setTimeout,
clearTimer = clearTimeout,
}) {
if (!Number.isSafeInteger(intervalSeconds) || intervalSeconds < 60) throw new Error('update interval must be at least 60 seconds')
this.check = check
this.onError = onError
this.intervalMs = intervalSeconds * 1_000
this.random = random
this.setTimer = setTimer
this.clearTimer = clearTimer
this.timer = undefined
this.enabled = false
}
schedule() {
const jitter = 0.9 + this.random() * 0.2
const timer = this.setTimer(async () => {
if (this.timer !== timer) return
this.timer = undefined
try {
await this.check()
} catch (error) {
await Promise.resolve().then(() => this.onError(error)).catch(() => {})
}
if (this.enabled && this.timer === undefined) this.schedule()
}, Math.round(this.intervalMs * jitter))
this.timer = timer
timer.unref?.()
}
start() {
this.enabled = true
if (this.timer === undefined) this.schedule()
}
configure({ enabled, intervalSeconds }) {
if (typeof enabled !== 'boolean') throw new Error('automatic check enabled must be boolean')
if (!Number.isSafeInteger(intervalSeconds) || intervalSeconds < 60) throw new Error('update interval must be at least 60 seconds')
this.stop()
this.intervalMs = intervalSeconds * 1_000
if (enabled) this.start()
}
stop() {
this.enabled = false
if (this.timer !== undefined) this.clearTimer(this.timer)
this.timer = undefined
}
}