@thatcompany/ts-tool
Version:
基于TypeScript编写的工具库
161 lines • 5.45 kB
JavaScript
"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