toad-scheduler
Version:
In-memory Node.js and browser job scheduler
111 lines • 4.51 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.LongIntervalJob = void 0;
const Job_1 = require("../../common/Job");
const Task_1 = require("../../common/Task");
const SimpleIntervalJob_1 = require("./SimpleIntervalJob");
const SimpleIntervalSchedule_1 = require("./SimpleIntervalSchedule");
const MAX_TIMEOUT_DURATION_MS = 2147483647;
class LongIntervalJob extends Job_1.Job {
constructor(schedule, task, options = {}) {
var _a;
super(options.id);
this.preventOverrun = (_a = options.preventOverrun) !== null && _a !== void 0 ? _a : true;
this.schedule = schedule;
this.task = task;
// Create a future date for this task and get the number of ms
const taskPeriod = (0, SimpleIntervalSchedule_1.toMsecs)(schedule);
// Initiate time-eating logic
if (taskPeriod >= MAX_TIMEOUT_DURATION_MS) {
this.setTimeEatingJob(taskPeriod);
}
}
setTimeEatingJob(taskPeriod) {
var _a;
const mainTaskExecutionDate = new Date();
mainTaskExecutionDate.setTime(Date.now() + taskPeriod);
const mainTaskExecutionTime = mainTaskExecutionDate.getTime();
const startingRemainingMs = mainTaskExecutionTime - Date.now();
const timeEater = new Task_1.Task('time eating task', () => {
var _a, _b;
const remainingMs = mainTaskExecutionTime - Date.now();
if (remainingMs >= MAX_TIMEOUT_DURATION_MS) {
/* istanbul ignore next */
(_a = this.childJob) === null || _a === void 0 ? void 0 : _a.stop();
this.childJob = new SimpleIntervalJob_1.SimpleIntervalJob({
milliseconds: Math.min(MAX_TIMEOUT_DURATION_MS - 1, remainingMs),
}, timeEater);
this.childJob.start();
}
else {
/* istanbul ignore next */
(_b = this.childJob) === null || _b === void 0 ? void 0 : _b.stop();
this.childJob = new SimpleIntervalJob_1.SimpleIntervalJob({
milliseconds: Math.min(MAX_TIMEOUT_DURATION_MS - 1, remainingMs),
}, new Task_1.Task('Final mile task', () => {
this.setTimeEatingJob((0, SimpleIntervalSchedule_1.toMsecs)(this.schedule));
return this.task.execute(this.id);
}));
this.childJob.start();
}
});
(_a = this.childJob) === null || _a === void 0 ? void 0 : _a.stop();
this.childJob = new SimpleIntervalJob_1.SimpleIntervalJob({
milliseconds: Math.min(MAX_TIMEOUT_DURATION_MS - 1, startingRemainingMs),
}, timeEater);
this.childJob.start();
}
/**
* Start the job.
*
* Lifecycle invariant: the underlying timer (or childJob, for the
* time-eating path used when the interval exceeds setInterval's
* ~24.85d cap) is brought up first, and any `runImmediately`
* execution happens last. Both paths share the rule, so a `stop()`
* issued from inside the immediate task always finds an active
* timer to clear (#176), and `runImmediately` is honored on the
* time-eating path too (#193, #212). `SimpleIntervalJob.start()`
* follows the same shape.
*/
start() {
if (this.childJob) {
this.childJob.start();
}
else {
const time = (0, SimpleIntervalSchedule_1.toMsecs)(this.schedule);
// Avoid starting duplicates and leaking previous timers
if (this.timer) {
this.stop();
}
this.timer = setInterval(() => {
if (!this.task.isExecuting || !this.preventOverrun) {
this.task.execute(this.id);
}
}, time);
}
if (this.schedule.runImmediately) {
this.task.execute(this.id);
}
}
stop() {
if (this.childJob) {
return this.childJob.stop();
}
if (!this.timer) {
return;
}
clearInterval(this.timer);
this.timer = undefined;
}
getStatus() {
if (this.childJob) {
return this.childJob.getStatus();
}
if (this.timer) {
return Job_1.JobStatus.RUNNING;
}
return Job_1.JobStatus.STOPPED;
}
}
exports.LongIntervalJob = LongIntervalJob;
//# sourceMappingURL=LongIntervalJob.js.map