Files
xen-orchestra/@xen-orchestra/cron/index.js
2022-03-25 17:10:22 +01:00

101 lines
2.3 KiB
JavaScript

'use strict'
const moment = require('moment-timezone')
const next = require('./next')
const parse = require('./parse')
const MAX_DELAY = 2 ** 31 - 1
class Job {
constructor(schedule, fn) {
let scheduledDate
const wrapper = () => {
const now = Date.now()
if (scheduledDate > now) {
// we're early, delay
//
// no need to check _isEnabled, we're just delaying the existing timeout
//
// see https://github.com/vatesfr/xen-orchestra/issues/4625
this._timeout = setTimeout(wrapper, scheduledDate - now)
return
}
this._isRunning = true
let result
try {
result = fn()
} catch (_) {
// catch any thrown value to ensure it does not break the job
}
let then
if (result != null && typeof (then = result.then) === 'function') {
then.call(result, scheduleNext, scheduleNext)
} else {
scheduleNext()
}
}
const scheduleNext = () => {
this._isRunning = false
if (this._isEnabled) {
const now = schedule._createDate()
scheduledDate = +next(schedule._schedule, now)
const delay = scheduledDate - now
this._timeout = delay < MAX_DELAY ? setTimeout(wrapper, delay) : setTimeout(scheduleNext, MAX_DELAY)
}
}
this._isEnabled = false
this._isRunning = false
this._scheduleNext = scheduleNext
this._timeout = undefined
}
start() {
this.stop()
this._isEnabled = true
if (!this._isRunning) {
this._scheduleNext()
}
}
stop() {
this._isEnabled = false
clearTimeout(this._timeout)
}
}
class Schedule {
constructor(pattern, zone = 'utc') {
this._schedule = parse(pattern)
this._createDate = zone.toLowerCase() === 'utc' ? moment.utc : zone === 'local' ? moment : () => moment.tz(zone)
}
createJob(fn) {
return new Job(this, fn)
}
next(n) {
const dates = new Array(n)
const schedule = this._schedule
let date = this._createDate()
for (let i = 0; i < n; ++i) {
dates[i] = (date = next(schedule, date)).toDate()
}
return dates
}
startJob(fn) {
const job = this.createJob(fn)
job.start()
return job.stop.bind(job)
}
}
const createSchedule = (...args) => new Schedule(...args)
exports.createSchedule = createSchedule