@vendure/core
Version:
A modern, headless ecommerce framework
178 lines • 8.16 kB
JavaScript
;
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SchedulerService = void 0;
const common_1 = require("@nestjs/common");
const cron_time_generator_1 = __importDefault(require("cron-time-generator"));
const croner_1 = require("croner");
const cronstrue_1 = __importDefault(require("cronstrue"));
const config_service_1 = require("../config/config.service");
const vendure_logger_1 = require("../config/logger/vendure-logger");
const process_context_1 = require("../process-context");
const noop_scheduler_strategy_1 = require("./noop-scheduler-strategy");
/**
* @description
* The service that is responsible for setting up and querying the scheduled tasks.
*
* @since 3.3.0
* @docsCategory scheduled-tasks
*/
let SchedulerService = class SchedulerService {
constructor(configService, processContext) {
this.configService = configService;
this.processContext = processContext;
this.jobs = new Map();
this.shouldRunTasks = false;
this.runningTasks = 0;
}
onApplicationBootstrap() {
var _a, _b;
const schedulerStrategy = this.configService.schedulerOptions.schedulerStrategy;
if (!schedulerStrategy || schedulerStrategy instanceof noop_scheduler_strategy_1.NoopSchedulerStrategy) {
vendure_logger_1.Logger.warn('No scheduler strategy is configured! Scheduled tasks will not be executed.');
vendure_logger_1.Logger.warn('Please use the `DefaultSchedulerPlugin` (or alternative) to enable scheduled tasks.');
return;
}
this.shouldRunTasks =
this.configService.schedulerOptions.runTasksInWorkerOnly === false ||
this.processContext.isWorker;
const scheduledTasks = (_a = this.configService.schedulerOptions.tasks) !== null && _a !== void 0 ? _a : [];
for (const task of scheduledTasks) {
const job = this.createCronJob(task);
const pattern = job.getPattern();
if (!pattern) {
vendure_logger_1.Logger.warn(`Invalid cron pattern for task ${task.id}`);
}
else {
if (this.shouldRunTasks) {
const schedule = cronstrue_1.default.toString(pattern);
vendure_logger_1.Logger.info(`Registered scheduled task: ${task.id} - ${schedule}`);
}
this.jobs.set(task.id, { task, job });
}
(_b = schedulerStrategy.registerTask) === null || _b === void 0 ? void 0 : _b.call(schedulerStrategy, task);
}
}
async onApplicationShutdown(signal) {
for (const job of this.jobs.values()) {
job.job.stop();
}
const startTime = Date.now();
// If any tasks are still running, wait a short time for them to finish
const maxWaitTime = 10000;
while (this.runningTasks > 0 && Date.now() - startTime < maxWaitTime) {
vendure_logger_1.Logger.warn(`Waiting for ${this.runningTasks} running tasks to finish before shutting down (signal: ${signal !== null && signal !== void 0 ? signal : 'unknown'})`);
await new Promise(resolve => setTimeout(resolve, 100));
}
}
/**
* @description
* Returns a list of all the scheduled tasks and their current status.
*/
getTaskList() {
return this.configService.schedulerOptions.schedulerStrategy
.getTasks()
.then(taskReports => taskReports.map(taskReport => this.createTaskInfo(taskReport)).filter(x => x !== undefined));
}
updateTask(input) {
return this.configService.schedulerOptions.schedulerStrategy.updateTask(input).then(taskReport => {
const taskInfo = this.createTaskInfo(taskReport);
if (!taskInfo) {
throw new Error(`Task ${input.id} not found`);
}
return taskInfo;
});
}
async runTask(taskId) {
const task = this.jobs.get(taskId);
if (!task) {
return {
success: false,
};
}
try {
await this.configService.schedulerOptions.schedulerStrategy.triggerTask(task.task);
return {
success: true,
};
}
catch (e) {
vendure_logger_1.Logger.error(`Could not trigger task: ` + e.message);
return {
success: false,
};
}
}
createTaskInfo(taskReport) {
var _a, _b, _c;
const job = (_a = this.jobs.get(taskReport.id)) === null || _a === void 0 ? void 0 : _a.job;
const task = (_b = this.jobs.get(taskReport.id)) === null || _b === void 0 ? void 0 : _b.task;
if (!job || !task) {
return;
}
const pattern = job.getPattern();
return {
id: taskReport.id,
description: (_c = task.options.description) !== null && _c !== void 0 ? _c : '',
schedule: pattern !== null && pattern !== void 0 ? pattern : 'unknown',
scheduleDescription: pattern ? cronstrue_1.default.toString(pattern) : 'unknown',
lastExecutedAt: taskReport.lastExecutedAt,
nextExecutionAt: job.nextRun(),
isRunning: taskReport.isRunning,
lastResult: taskReport.lastResult,
enabled: taskReport.enabled,
};
}
createCronJob(task) {
const schedulerStrategy = this.configService.schedulerOptions.schedulerStrategy;
const protectCallback = (_job) => {
const currentRun = _job.currentRun();
if (currentRun) {
vendure_logger_1.Logger.warn(`Task invocation of ${task.id} at ${new Date().toISOString()} was blocked because an existing task is still running at ${currentRun.toISOString()}`);
}
};
const schedule = typeof task.options.schedule === 'function'
? task.options.schedule(cron_time_generator_1.default)
: task.options.schedule;
const job = new croner_1.Cron(schedule, {
name: task.id,
protect: task.options.preventOverlap ? protectCallback : undefined,
}, () => {
if (this.shouldRunTasks) {
// Only execute the cron task on the worker process
// so that any expensive logic does not affect
// the responsiveness of server processes
this.runningTasks++;
try {
schedulerStrategy.executeTask(task)(job);
}
catch (e) {
const message = e instanceof Error ? e.message : String(e);
vendure_logger_1.Logger.error(`Error executing scheduled task ${task.id}: ${message}`);
}
finally {
this.runningTasks--;
}
}
});
return job;
}
};
exports.SchedulerService = SchedulerService;
exports.SchedulerService = SchedulerService = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [config_service_1.ConfigService,
process_context_1.ProcessContext])
], SchedulerService);
//# sourceMappingURL=scheduler.service.js.map