perf: 执行队列数量支持设置

This commit is contained in:
xiaojunnuo
2025-12-26 18:17:05 +08:00
parent 888d9591fe
commit cd944882c3
9 changed files with 125 additions and 60 deletions

View File

@@ -2,3 +2,4 @@ export * from './service/plus-service.js';
export * from './service/file-service.js';
export * from './service/encryptor.js';
export * from './service/ocr-service.js';
export * from './service/executor-queue.js';

View File

@@ -0,0 +1,79 @@
import { logger } from "@certd/basic";
export type TaskItem = {
task: ()=>Promise<void>;
}
export class UserTaskQueue{
userId: number;
pendingQueue: TaskItem[] = [];
runningQueue: TaskItem[] = [];
getMaxRunningCount: ()=>number ;
constructor(req: { userId: number ,getMaxRunningCount: ()=>number }) {
this.userId = req.userId;
this.getMaxRunningCount = req.getMaxRunningCount ;
}
addTask(task: TaskItem) {
this.pendingQueue.push(task);
this.runTask();
}
runTask() {
logger.info(`[user_${this.userId}]当前运行队列:${this.runningQueue.length}, 等待队列:${this.pendingQueue.length},最大运行队列:${this.getMaxRunningCount()}`);
if (this.runningQueue.length >= this.getMaxRunningCount()) {
return;
}
if (this.pendingQueue.length === 0) {
return;
}
const task = this.pendingQueue.shift();
if (!task) {
return;
}
// 执行任务
this.runningQueue.push(task);
const call = async ()=>{
try{
await task.task();
}finally{
// 任务执行完成,从运行队列中移除
const index = this.runningQueue.indexOf(task);
if (index > -1) {
this.runningQueue.splice(index, 1);
}
// 继续执行下一个任务
this.runTask();
}
}
logger.info(`[user_${this.userId}]执行任务,当前运行队列:${this.runningQueue.length}, 等待队列:${this.pendingQueue.length}`);
call()
}
}
export class ExecutorQueue{
queues: Record<number, UserTaskQueue> = {};
maxRunningCount: number = 8;
setMaxRunningCount(count: number) {
this.maxRunningCount = count;
}
getUserQueue(userId: number) {
const userQueue = this.queues[userId];
if (!userQueue) {
this.queues[userId] = new UserTaskQueue({ userId, getMaxRunningCount: ()=>this.maxRunningCount });
}
return this.queues[userId];
}
addTask(userId: number, task: TaskItem) {
const userQueue = this.getUserQueue(userId);
userQueue.addTask(task);
}
}
export const executorQueue = new ExecutorQueue();

View File

@@ -43,12 +43,16 @@ export class SysPublicSettings extends BaseSettings {
//流水线是否启用有效期
pipelineValidTimeEnabled?: boolean = false;
//证书域名添加到监控
certDomainAddToMonitorEnabled?: boolean = false;
// 固定证书有效期天数0表示不固定
fixedCertExpireDays?: number;
//默认到期前更新天数
defaultCertRenewDays?: number;
// 第三方OAuth配置
oauthEnabled?: boolean = false;
oauthProviders: Record<string, {
@@ -73,6 +77,8 @@ export class SysPrivateSettings extends BaseSettings {
httpRequestTimeout?: number = 30;
pipelineMaxRunningCount?: number;
sms?: {
type?: string;
config?: any;

View File

@@ -8,6 +8,7 @@ import { BaseService } from '../../../basic/index.js';
import { cache, logger, setGlobalProxy } from '@certd/basic';
import * as dns from 'node:dns';
import {mergeUtils} from "@certd/basic";
import { executorQueue } from '../../basic/service/executor-queue.js';
const {merge} = mergeUtils;
/**
* 设置
@@ -140,6 +141,10 @@ export class SysSettingsService extends BaseService<SysSettingsEntity> {
if (bean.dnsResultOrder) {
dns.setDefaultResultOrder(bean.dnsResultOrder as any);
}
if (bean.pipelineMaxRunningCount){
executorQueue.setMaxRunningCount(bean.pipelineMaxRunningCount);
}
}
async updateByKey(key: string, setting: any) {

View File

@@ -759,6 +759,14 @@ export default {
certDomainAddToMonitorEnabled: "证书域名添加到证书监控",
certDomainAddToMonitorEnabledHelper: "创建证书流水线时是否可以选择将域名添加到证书监控",
defaultCertRenewDays: "默认到期前更新天数",
defaultCertRenewDaysHelper: "创建证书流水线时,默认的证书到期前更新天数",
defaultCertRenewDaysRecommend: "默认值15",
pipelineMaxRunningCount: "同时最大运行流水线数量",
pipelineMaxRunningCountHelper: "同一个用户同时运行的最大流水线数量避免同时触发太多导致ACME账户被限制",
pipelineMaxRunningCountRecommend: "推荐5-10",
fixedCertExpireDays: "固定证书有效期天数",
fixedCertExpireDaysHelper: "固定证书有效期天数,有助于列表进度条整齐显示",
fixedCertExpireDaysRecommend: "推荐90",

View File

@@ -54,6 +54,9 @@ export type SysPublicSetting = {
//流水线是否启用有效期
pipelineValidTimeEnabled?: boolean;
// 默认到期前更新天数
defaultCertRenewDays?: number;
//证书域名添加到监控
certDomainAddToMonitorEnabled?: boolean;
@@ -86,6 +89,9 @@ export type SysPrivateSetting = {
httpsProxy?: string;
dnsResultOrder?: string;
commonCnameEnabled?: boolean;
// 同一个用户同时最大运行流水线数量
pipelineMaxRunningCount?: number;
sms?: {
type?: string;
config?: any;

View File

@@ -26,12 +26,26 @@
<a-form-item :label="t('certd.sys.setting.fixedCertExpireDays')" :name="['public', 'fixedCertExpireDays']">
<div class="flex items-center">
<a-input-number v-model:value="formState.public.fixedCertExpireDays" :placeholder="t('certd.sys.setting.fixedCertExpireDaysRecommend')" />
<a-input-number v-model:value="formState.public.fixedCertExpireDays" :disabled="!settingsStore.isPlus" :placeholder="t('certd.sys.setting.fixedCertExpireDaysRecommend')" />
<vip-button class="ml-5" mode="button"></vip-button>
</div>
<div class="helper">{{ t("certd.sys.setting.fixedCertExpireDaysHelper") }}</div>
</a-form-item>
<a-form-item :label="t('certd.sys.setting.defaultCertRenewDays')" :name="['public', 'defaultCertRenewDays']">
<div class="flex items-center">
<a-input-number v-model:value="formState.public.defaultCertRenewDays" :placeholder="t('certd.sys.setting.defaultCertRenewDaysRecommend')" />
</div>
<div class="helper">{{ t("certd.sys.setting.defaultCertRenewDaysHelper") }}</div>
</a-form-item>
<a-form-item :label="t('certd.sys.setting.pipelineMaxRunningCount')" :name="['private', 'pipelineMaxRunningCount']">
<div class="flex items-center">
<a-input-number v-model:value="formState.private.pipelineMaxRunningCount" :placeholder="t('certd.sys.setting.pipelineMaxRunningCountRecommend')" />
</div>
<div class="helper">{{ t("certd.sys.setting.pipelineMaxRunningCountHelper") }}</div>
</a-form-item>
<a-form-item label=" " :colon="false" :wrapper-col="{ span: 8 }">
<a-button :loading="saveLoading" type="primary" html-type="submit">{{ t("certd.saveButton") }}</a-button>
</a-form-item>

View File

@@ -1,54 +0,0 @@
import { logger } from "@certd/basic";
export type TaskItem = {
task: ()=>Promise<void>;
}
export class ExecutorQueue{
pendingQueue: TaskItem[] = [];
runningQueue: TaskItem[] = [];
maxRunningCount: number = 10;
setMaxRunningCount(count: number) {
this.maxRunningCount = count;
}
addTask(task: TaskItem) {
this.pendingQueue.push(task);
this.runTask();
}
runTask() {
logger.info(`当前运行队列:${this.runningQueue.length}, 等待队列:${this.pendingQueue.length}`);
if (this.runningQueue.length >= this.maxRunningCount) {
logger.info(`当前运行队列已满,等待队列:${this.pendingQueue.length}`);
return;
}
if (this.pendingQueue.length === 0) {
return;
}
const task = this.pendingQueue.shift();
if (!task) {
return;
}
// 执行任务
this.runningQueue.push(task);
const call = async ()=>{
try{
await task.task();
}finally{
// 任务执行完成,从运行队列中移除
const index = this.runningQueue.indexOf(task);
if (index > -1) {
this.runningQueue.splice(index, 1);
}
// 继续执行下一个任务
this.runTask();
}
}
call()
}
}
export const executorQueue = new ExecutorQueue();

View File

@@ -47,7 +47,7 @@ import { CertInfoService } from "../../monitor/service/cert-info-service.js";
import { TaskServiceBuilder } from "./getter/task-service-getter.js";
import { nanoid } from "nanoid";
import { set } from "lodash-es";
import { executorQueue } from "./executor-queue.js";
import { executorQueue } from "@certd/lib-server";
const runningTasks: Map<string | number, Executor> = new Map();
@@ -373,7 +373,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
return;
}
for (const trigger of pipeline.triggers) {
this.registerCron(pipeline.id, trigger);
this.registerCron(pipeline.id, pipeline.userId, trigger);
}
if (immediateTriggerOnce) {
@@ -461,7 +461,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
logger.info("当前定时器数量:", this.cron.getTaskSize());
}
registerCron(pipelineId, trigger) {
registerCron(pipelineId: number, userId: number, trigger) {
if (pipelineId == null) {
logger.warn("pipelineId为空无法注册定时任务");
return;
@@ -491,7 +491,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
return;
}
//加入执行队列
executorQueue.addTask({
executorQueue.addTask(userId, {
task: async () => {
try {
await this.run(pipelineId, triggerId);
@@ -678,7 +678,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
this.cron.remove(key);
triggerType = null;
} else {
logger.info(`timer trigger:${key}, ${found.title}, ${found.props}`);
logger.info(`timer trigger:${key}, ${found.title}, ${JSON.stringify(found.props)}`);
triggerType = "timer";
}
}