mirror of https://github.com/certd/certd
fix: 修复在相同的cron时偶尔无法触发定时任务的bug
parent
1cf8d4e5e7
commit
680941af11
|
@ -3,9 +3,8 @@ import { logger } from "../utils/index.js";
|
||||||
|
|
||||||
const SecreteKey =
|
const SecreteKey =
|
||||||
"LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JSUJDZ0tDQVFFQXY3TGtMaUp1dGM0NzhTU3RaTExjajVGZXh1YjJwR2NLMGxwa0hwVnlZWjhMY29rRFhuUlAKUGQ5UlJSTVRTaGJsbFl2Mzd4QUhOV1ZIQ0ZsWHkrQklVU001bUlBU1NDQTV0azlJNmpZZ2F4bEFDQm1BY0lGMwozKzBjeGZIYVkrVW9YdVluMkZ6YUt2Ym5GdFZIZ0lkMDg4a3d4clZTZzlCT3BDRVZIR1pxR2I5TWN5MXVHVXhUClFTVENCbmpoTWZlZ0p6cXVPYWVOY0ZPSE5tbmtWRWpLTythbTBPeEhNS1lyS3ZnQnVEbzdoVnFENlBFMUd6V3AKZHdwZUV4QXZDSVJxL2pWTkdRK3FtMkRWOVNJZ3U5bmF4MktmSUtFeU50dUFFS1VpekdqL0VmRFhDM1cxMExhegpKaGNYNGw1SUFZU1o3L3JWVmpGbExWSVl0WDU1T054L1Z3SURBUUFCCi0tLS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0K";
|
"LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JSUJDZ0tDQVFFQXY3TGtMaUp1dGM0NzhTU3RaTExjajVGZXh1YjJwR2NLMGxwa0hwVnlZWjhMY29rRFhuUlAKUGQ5UlJSTVRTaGJsbFl2Mzd4QUhOV1ZIQ0ZsWHkrQklVU001bUlBU1NDQTV0azlJNmpZZ2F4bEFDQm1BY0lGMwozKzBjeGZIYVkrVW9YdVluMkZ6YUt2Ym5GdFZIZ0lkMDg4a3d4clZTZzlCT3BDRVZIR1pxR2I5TWN5MXVHVXhUClFTVENCbmpoTWZlZ0p6cXVPYWVOY0ZPSE5tbmtWRWpLTythbTBPeEhNS1lyS3ZnQnVEbzdoVnFENlBFMUd6V3AKZHdwZUV4QXZDSVJxL2pWTkdRK3FtMkRWOVNJZ3U5bmF4MktmSUtFeU50dUFFS1VpekdqL0VmRFhDM1cxMExhegpKaGNYNGw1SUFZU1o3L3JWVmpGbExWSVl0WDU1T054L1Z3SURBUUFCCi0tLS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0K";
|
||||||
|
const appKey = "z4nXOeTeSnnpUpnmsV";
|
||||||
export type LicenseVerifyReq = {
|
export type LicenseVerifyReq = {
|
||||||
appKey: string;
|
|
||||||
subjectId: string;
|
subjectId: string;
|
||||||
license: string;
|
license: string;
|
||||||
};
|
};
|
||||||
|
@ -33,13 +32,10 @@ class LicenseVerifier {
|
||||||
licenseReq?: LicenseVerifyReq = undefined;
|
licenseReq?: LicenseVerifyReq = undefined;
|
||||||
async reVerify(req: LicenseVerifyReq) {
|
async reVerify(req: LicenseVerifyReq) {
|
||||||
this.checked = false;
|
this.checked = false;
|
||||||
//@ts-ignore
|
|
||||||
// globalThis._certd_license_.isPlus = false;
|
|
||||||
return await this.verify(req);
|
return await this.verify(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
setPlus(value: boolean) {
|
setPlus(value: boolean) {
|
||||||
//@ts-ignore
|
|
||||||
holder.isPlus = value;
|
holder.isPlus = value;
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
@ -60,7 +56,7 @@ class LicenseVerifier {
|
||||||
logger.warn("授权已过期");
|
logger.warn("授权已过期");
|
||||||
return this.setPlus(false);
|
return this.setPlus(false);
|
||||||
}
|
}
|
||||||
const content = `${this.licenseReq.appKey},${this.licenseReq.subjectId},${json.code},${json.secret},${json.activeTime},${json.duration},${json.expireTime},${json.version}`;
|
const content = `${appKey},${this.licenseReq.subjectId},${json.code},${json.secret},${json.activeTime},${json.duration},${json.expireTime},${json.version}`;
|
||||||
const publicKey = Buffer.from(SecreteKey, "base64").toString();
|
const publicKey = Buffer.from(SecreteKey, "base64").toString();
|
||||||
const res = this.verifySignature(content, json.signature, publicKey);
|
const res = this.verifySignature(content, json.signature, publicKey);
|
||||||
this.checked = true;
|
this.checked = true;
|
||||||
|
|
|
@ -336,6 +336,21 @@ function install(app: App, options: any = {}) {
|
||||||
return columnProps;
|
return columnProps;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
registerMergeColumnPlugin({
|
||||||
|
name: "resize-column-plugin",
|
||||||
|
order: 2,
|
||||||
|
handle: (columnProps: ColumnCompositionProps) => {
|
||||||
|
if (!columnProps.column) {
|
||||||
|
columnProps.column = {};
|
||||||
|
}
|
||||||
|
columnProps.column.resizable = true;
|
||||||
|
if (!columnProps.column.width) {
|
||||||
|
columnProps.column.width = 100;
|
||||||
|
}
|
||||||
|
return columnProps;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
|
@ -6,12 +6,10 @@ export function useReference(form: any) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (const reference of form.reference) {
|
for (const reference of form.reference) {
|
||||||
debugger;
|
|
||||||
_.set(
|
_.set(
|
||||||
form,
|
form,
|
||||||
reference.dest,
|
reference.dest,
|
||||||
compute<any>((scope) => {
|
compute<any>((scope) => {
|
||||||
debugger;
|
|
||||||
return _.get(scope, reference.src);
|
return _.get(scope, reference.src);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"better-sqlite3": "^11.1.2",
|
"better-sqlite3": "^11.1.2",
|
||||||
"cache-manager": "^3.6.3",
|
"cache-manager": "^3.6.3",
|
||||||
|
"cron-parser": "^4.9.0",
|
||||||
"dayjs": "^1.11.7",
|
"dayjs": "^1.11.7",
|
||||||
"glob": "^10.4.5",
|
"glob": "^10.4.5",
|
||||||
"https-proxy-agent": "^7.0.4",
|
"https-proxy-agent": "^7.0.4",
|
||||||
|
@ -56,7 +57,6 @@
|
||||||
"md5": "^2.3.0",
|
"md5": "^2.3.0",
|
||||||
"mwtsc": "^1.4.0",
|
"mwtsc": "^1.4.0",
|
||||||
"nanoid": "^4.0.0",
|
"nanoid": "^4.0.0",
|
||||||
"node-cron": "^3.0.2",
|
|
||||||
"nodemailer": "^6.9.3",
|
"nodemailer": "^6.9.3",
|
||||||
"pg": "^8.12.0",
|
"pg": "^8.12.0",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
|
|
|
@ -35,7 +35,11 @@ export class AutoInitSite {
|
||||||
|
|
||||||
// 授权许可
|
// 授权许可
|
||||||
const licenseInfo: SysLicenseInfo = await this.sysSettingsService.getSetting(SysLicenseInfo);
|
const licenseInfo: SysLicenseInfo = await this.sysSettingsService.getSetting(SysLicenseInfo);
|
||||||
await verify(licenseInfo.license);
|
const req = {
|
||||||
|
subjectId: installInfo.siteId,
|
||||||
|
license: licenseInfo.license,
|
||||||
|
};
|
||||||
|
await verify(req);
|
||||||
|
|
||||||
logger.info('初始化站点完成');
|
logger.info('初始化站点完成');
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,7 +120,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.info('定时器数量:', this.cron.getListSize());
|
logger.info('定时器数量:', this.cron.getTaskSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
async registerTriggers(pipeline?: Pipeline, immediateTriggerOnce = false) {
|
async registerTriggers(pipeline?: Pipeline, immediateTriggerOnce = false) {
|
||||||
|
@ -193,7 +193,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
logger.info('当前定时器数量:', this.cron.getListSize());
|
logger.info('当前定时器数量:', this.cron.getTaskSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
async run(id: number, triggerId: string) {
|
async run(id: number, triggerId: string) {
|
||||||
|
@ -212,6 +212,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
||||||
const onChanged = async (history: RunHistory) => {
|
const onChanged = async (history: RunHistory) => {
|
||||||
//保存执行历史
|
//保存执行历史
|
||||||
try {
|
try {
|
||||||
|
logger.info('保存执行历史:', history.id);
|
||||||
await this.saveHistory(history);
|
await this.saveHistory(history);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const pipelineEntity = new PipelineEntity();
|
const pipelineEntity = new PipelineEntity();
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import cron from 'node-cron';
|
import parser from 'cron-parser';
|
||||||
export type CronTask = {
|
import { ILogger } from '@certd/pipeline';
|
||||||
|
|
||||||
|
export type CronTaskReq = {
|
||||||
/**
|
/**
|
||||||
* 为空则为单次执行
|
* 为空则为单次执行
|
||||||
*/
|
*/
|
||||||
|
@ -7,39 +9,90 @@ export type CronTask = {
|
||||||
job: () => Promise<void>;
|
job: () => Promise<void>;
|
||||||
name: string;
|
name: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export class CronTask {
|
||||||
|
logger: ILogger;
|
||||||
|
cron: string;
|
||||||
|
job: () => Promise<void>;
|
||||||
|
name: string;
|
||||||
|
stoped = false;
|
||||||
|
|
||||||
|
timeoutId: any;
|
||||||
|
|
||||||
|
constructor(req: CronTaskReq, logger: ILogger) {
|
||||||
|
this.cron = req.cron;
|
||||||
|
this.job = req.job;
|
||||||
|
this.name = req.name;
|
||||||
|
this.logger = logger;
|
||||||
|
this.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
if (!this.cron) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.stoped) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const interval = parser.parseExpression(this.cron);
|
||||||
|
const next = interval.next().getTime();
|
||||||
|
const now = Date.now();
|
||||||
|
const delay = next - now;
|
||||||
|
this.timeoutId = setTimeout(async () => {
|
||||||
|
try {
|
||||||
|
if (this.stoped) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await this.job();
|
||||||
|
} catch (e) {
|
||||||
|
this.logger.error(`[cron] job error : [${this.name}]`, e);
|
||||||
|
}
|
||||||
|
this.start();
|
||||||
|
}, delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
stop() {
|
||||||
|
this.stoped = true;
|
||||||
|
clearTimeout(this.timeoutId);
|
||||||
|
}
|
||||||
|
}
|
||||||
export class Cron {
|
export class Cron {
|
||||||
logger;
|
logger: ILogger;
|
||||||
immediateTriggerOnce: boolean;
|
immediateTriggerOnce: boolean;
|
||||||
constructor(opts) {
|
|
||||||
|
bucket: Record<string, CronTask> = {};
|
||||||
|
|
||||||
|
constructor(opts: any) {
|
||||||
this.logger = opts.logger;
|
this.logger = opts.logger;
|
||||||
this.immediateTriggerOnce = opts.immediateTriggerOnce;
|
this.immediateTriggerOnce = opts.immediateTriggerOnce;
|
||||||
}
|
}
|
||||||
|
|
||||||
register(task: CronTask) {
|
register(req: CronTaskReq) {
|
||||||
if (!task.cron) {
|
if (!req.cron) {
|
||||||
this.logger.info(`[cron] register once : [${task.name}]`);
|
this.logger.info(`[cron] register once : [${req.name}]`);
|
||||||
task.job();
|
req.job().catch(e => {
|
||||||
|
this.logger.error(`job execute error : [${req.name}]`, e);
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.logger.info(`[cron] register cron : [${task.name}] ,${task.cron}`);
|
this.logger.info(`[cron] register cron : [${req.name}] ,${req.cron}`);
|
||||||
cron.schedule(task.cron, task.job, {
|
|
||||||
name: task.name,
|
const task = new CronTask(req, this.logger);
|
||||||
});
|
this.bucket[task.name] = task;
|
||||||
this.logger.info('当前定时任务数量:', this.getListSize());
|
this.logger.info('当前定时任务数量:', this.getTaskSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
remove(taskName: string) {
|
remove(taskName: string) {
|
||||||
this.logger.info(`[cron] remove : [${taskName}]`);
|
this.logger.info(`[cron] remove : [${taskName}]`);
|
||||||
const tasks = cron.getTasks() as Map<any, any>;
|
const task = this.bucket[taskName];
|
||||||
const node = tasks.get(taskName);
|
if (task) {
|
||||||
if (node) {
|
task.stop();
|
||||||
node.stop();
|
delete this.bucket[taskName];
|
||||||
tasks.delete(taskName);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getListSize() {
|
getTaskSize() {
|
||||||
const tasks = cron.getTasks();
|
const tasks = Object.keys(this.bucket);
|
||||||
return tasks.size;
|
return tasks.length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,5 +32,5 @@ export class SysLicenseInfo extends BaseSettings {
|
||||||
static __title__ = '授权许可信息';
|
static __title__ = '授权许可信息';
|
||||||
static __key__ = 'sys.license';
|
static __key__ = 'sys.license';
|
||||||
static __access__ = 'private';
|
static __access__ = 'private';
|
||||||
license: string;
|
license?: string;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue