UNPKG

@thatcompany/ts-tool

Version:

基于TypeScript编写的工具库

161 lines 5.45 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ICronTaskService = void 0; const timer_1 = require("../../../../timer"); /** * 调度服务接口 * * 记得实现 @TaskRegister装饰器修饰的类,否则不会被扫描到 * * @example * ```typescript * @TaskCronService * class TestCronTaskService extends ICronTaskService { * NAME: string = 'TestCronTaskService'; * CRON_EXP: string = '*\/10 * * * * *'; * async collection(): Promise<void> { * Array.from({ length: 3 }, (_, i) => `测试定时任务${i + 1}`).forEach((name, i) => { * this.addPending(i + 1, name); * }); * } * async execute(task: TThreadChild<any>): Promise<TCronExecuteResult<any>> { * return { task, success: true }; * } * override async executeEnd(data: any): Promise<void> { * Logger.info(data.task, data.success); * } * } * ``` */ class ICronTaskService { // 调度器名称 NAME = 'ICronTaskService'; // 调度器名称 DESCRIPTION = '调度器服务接口'; // 调度器表达式 CRON_EXP = '* * * * * */1'; // 调度任务的并发等待时间 WAIT_TIME = { execute: 100, plus: 100, repeat: 1000 }; // 调度任务的重复丢弃策略 DISCARD = { pending: false, ready: false, running: false }; // 调度器挂起的任务Map _queuePending = new Map(); // 调度器预备的任务队列 _queueReady = []; // 调度器运行的KEY集合 _queueRunning = new Set(); // 调度器运行锁 _runLock = false; // 调度器加线程锁 _plusLock = false; // 调度器最大线程数 QUEUE_MAX = 12; /** * 初始化调度器 * @param name 调度器名称 * @param description 调度器描述 * @param cronExp 调度器表达式 */ init(name, description, cronExp) { this.NAME = name; this.DESCRIPTION = description; this.CRON_EXP = cronExp; } // 启动调度器 async run() { await this.collection(); this.activeThread(); } /** * 添加调度任务 * @param key 键 * @param value 值 * @param update 是否强制更新已经存在的任务 */ addPending(key, value, update = !this.DISCARD.pending) { if (this._queuePending.has(key) && !update) { return; } this._queuePending.set(key, value); } /** * 移除调度任务 * @param key 键 */ removePending(key) { if (this._queuePending.has(key)) { this._queuePending.delete(key); } } /** * 增加线程 * 增加线程时,会先上锁,然后将挂起的任务全部加入到线程队列中 */ plusThread() { this._plusLock = true; // this._queueReady.push(this._queuePending); // 将 this._queueReady 和 this._queuePending 比较, _queueThread有的任务会被丢弃 this._queuePending.forEach((value, key) => { // 检查 _queueReady 中是否已有该任务 const exists = this._queueReady.some((threadMap) => threadMap.key === key); if (!exists) { // 如果不存在,则添加到 _queueReady this._queueReady.push({ key, value }); } else if (!this.DISCARD.ready) { // 如果存在,且不允许丢弃,则更新该任务 const index = this._queueReady.findIndex((threadMap) => threadMap.key === key); this._queueReady[index].value = value; } }); // 清空 _queuePending this._queuePending.clear(); this._plusLock = false; } /** * 激活线程 * 将挂起的任务全部加入到线程队列中 * 线程未激活则先上锁,再激活线程,防止多次激活 */ activeThread() { this.plusThread(); if (this._runLock || this._queueReady.length === 0) { return; } this._runLock = true; this.executeAll(); } /** * 执行所有任务 * 循环执行所有任务,直到所有任务执行完毕 */ async executeAll() { while (this._runLock && this._queueReady.length > 0) { if (this._queueRunning.size < this.QUEUE_MAX && this._queueReady.length > 0) { // TODO: 需要中断更新任务机制、超时机制、失败重试机制 if (this._queueRunning.has(this._queueReady[0].key)) { await timer_1.Timer.sleep(this.WAIT_TIME.repeat); // Logger.warn(`任务${this._queueReady[0].key}正在执行,跳过`); continue; } const task = this._queueReady.shift(); this._queueRunning.add(task.key); (async () => { try { await this.executeEnd(await this.execute(task)); } finally { this._queueRunning.delete(task.key); } })(); } await timer_1.Timer.sleep(this.WAIT_TIME.execute); while (this._plusLock) { await timer_1.Timer.sleep(this.WAIT_TIME.plus); } } this._runLock = false; } } exports.ICronTaskService = ICronTaskService; //# sourceMappingURL=ICronTaskService.js.map