mirror of
https://github.com/certd/certd.git
synced 2026-04-24 04:17:25 +08:00
perf: 修复检查全部某些情况下无效的bug,优化公共触发站点证书检查定时逻辑
This commit is contained in:
@@ -13,13 +13,11 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import parser from "cron-parser";
|
|
||||||
import { computed, ref } from "vue";
|
import { computed, ref } from "vue";
|
||||||
import dayjs from "dayjs";
|
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { getCronNextTimes } from "/@/components/cron-editor/utils";
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
import { getCronNextTimes } from "/@/components/cron-editor/utils";
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: "CronEditor",
|
name: "CronEditor",
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ export class SiteInfoController extends CrudController<SiteInfoService> {
|
|||||||
@Post('/checkAll', { description: Constants.per.authOnly, summary: "检查所有站点监控" })
|
@Post('/checkAll', { description: Constants.per.authOnly, summary: "检查所有站点监控" })
|
||||||
async checkAll() {
|
async checkAll() {
|
||||||
const { projectId, userId } = await this.getProjectUserIdWrite()
|
const { projectId, userId } = await this.getProjectUserIdWrite()
|
||||||
await this.service.checkAllByUsers(userId,projectId);
|
this.service.triggerJobOnce(userId,projectId);
|
||||||
return this.ok();
|
return this.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,18 @@
|
|||||||
import {Autoload, Config, Init, Inject, Scope, ScopeEnum} from '@midwayjs/core';
|
import { logger } from '@certd/basic';
|
||||||
import {PipelineService} from '../pipeline/service/pipeline-service.js';
|
import { SysSettingsService, SysSiteInfo } from '@certd/lib-server';
|
||||||
import {logger} from '@certd/basic';
|
import { getPlusInfo, isPlus } from "@certd/plus-core";
|
||||||
import {SysSettingsService, SysSiteInfo} from '@certd/lib-server';
|
import { Autoload, Config, Init, Inject, Scope, ScopeEnum } from '@midwayjs/core';
|
||||||
import {SiteInfoService} from '../monitor/index.js';
|
|
||||||
import {Cron} from '../cron/cron.js';
|
|
||||||
import {UserSettingsService} from "../mine/service/user-settings-service.js";
|
|
||||||
import {UserSiteMonitorSetting} from "../mine/service/models.js";
|
|
||||||
import {getPlusInfo, isPlus} from "@certd/plus-core";
|
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import {NotificationService} from "../pipeline/service/notification-service.js";
|
import { Between } from "typeorm";
|
||||||
import {UserService} from "../sys/authority/service/user-service.js";
|
|
||||||
import {Between} from "typeorm";
|
|
||||||
import { DomainService } from '../cert/service/domain-service.js';
|
import { DomainService } from '../cert/service/domain-service.js';
|
||||||
|
import { Cron } from '../cron/cron.js';
|
||||||
|
import { UserSiteMonitorSetting } from "../mine/service/models.js";
|
||||||
|
import { UserSettingsService } from "../mine/service/user-settings-service.js";
|
||||||
|
import { SiteInfoService } from '../monitor/index.js';
|
||||||
|
import { NotificationService } from "../pipeline/service/notification-service.js";
|
||||||
|
import { PipelineService } from '../pipeline/service/pipeline-service.js';
|
||||||
|
import { UserService } from "../sys/authority/service/user-service.js";
|
||||||
|
import { ProjectService } from '../sys/enterprise/service/project-service.js';
|
||||||
|
|
||||||
@Autoload()
|
@Autoload()
|
||||||
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
||||||
@@ -47,6 +48,9 @@ export class AutoCRegisterCron {
|
|||||||
|
|
||||||
@Inject()
|
@Inject()
|
||||||
domainService: DomainService;
|
domainService: DomainService;
|
||||||
|
@Inject()
|
||||||
|
projectService: ProjectService;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Init()
|
@Init()
|
||||||
@@ -72,9 +76,23 @@ export class AutoCRegisterCron {
|
|||||||
|
|
||||||
async registerSiteMonitorCron() {
|
async registerSiteMonitorCron() {
|
||||||
//先注册公共job
|
//先注册公共job
|
||||||
await this.siteInfoService.registerSiteMonitorJob()
|
logger.info(`注册公共站点证书检查定时任务`)
|
||||||
|
const randomMinute = Math.floor(Math.random() * 60)
|
||||||
|
this.cron.register({
|
||||||
|
name: 'siteMonitor',
|
||||||
|
cron: `0 ${randomMinute} 0 * * *`,
|
||||||
|
job:async ()=>{
|
||||||
|
logger.info(`开始公共站点证书检查任务`)
|
||||||
|
await this.siteInfoService.triggerCommonJob()
|
||||||
|
logger.info(`公共站点证书检查任务完成`)
|
||||||
|
},
|
||||||
|
});
|
||||||
|
logger.info(`注册公共站点证书检查定时任务完成`)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//注册用户独立的检查时间
|
//注册用户独立的检查时间
|
||||||
|
logger.info(`注册用户独立站点证书检查定时任务`)
|
||||||
const monitorSettingList = await this.userSettingsService.list({
|
const monitorSettingList = await this.userSettingsService.list({
|
||||||
query:{
|
query:{
|
||||||
key: UserSiteMonitorSetting.__key__,
|
key: UserSiteMonitorSetting.__key__,
|
||||||
@@ -87,10 +105,11 @@ export class AutoCRegisterCron {
|
|||||||
}
|
}
|
||||||
await this.siteInfoService.registerSiteMonitorJob(item.userId,item.projectId)
|
await this.siteInfoService.registerSiteMonitorJob(item.userId,item.projectId)
|
||||||
}
|
}
|
||||||
|
logger.info(`注册用户独立站点证书检查定时任务完成`)
|
||||||
|
|
||||||
if (this.immediateTriggerSiteMonitor) {
|
if (this.immediateTriggerSiteMonitor) {
|
||||||
logger.info(`立即触发一次站点证书检查任务`)
|
logger.info(`立即触发一次公共站点证书检查任务`)
|
||||||
await this.siteInfoService.triggerJobOnce()
|
await this.siteInfoService.triggerCommonJob()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import {Inject, Provide, Scope, ScopeEnum} from "@midwayjs/core";
|
import {Inject, Provide, Scope, ScopeEnum} from "@midwayjs/core";
|
||||||
import {BaseService, NeedSuiteException, NeedVIPException, SysSettingsService} from "@certd/lib-server";
|
import {BaseService, Constants, NeedSuiteException, NeedVIPException, SysSettingsService} from "@certd/lib-server";
|
||||||
import {InjectEntityModel} from "@midwayjs/typeorm";
|
import {InjectEntityModel} from "@midwayjs/typeorm";
|
||||||
import {In, Repository} from "typeorm";
|
import {In, Repository} from "typeorm";
|
||||||
import {SiteInfoEntity} from "../entity/site-info.js";
|
import {SiteInfoEntity} from "../entity/site-info.js";
|
||||||
@@ -19,6 +19,8 @@ import { dnsContainer } from "./dns-custom.js";
|
|||||||
import { merge } from "lodash-es";
|
import { merge } from "lodash-es";
|
||||||
import { JobHistoryService } from "./job-history-service.js";
|
import { JobHistoryService } from "./job-history-service.js";
|
||||||
import { JobHistoryEntity } from "../entity/job-history.js";
|
import { JobHistoryEntity } from "../entity/job-history.js";
|
||||||
|
import { UserService } from "../../sys/authority/service/user-service.js";
|
||||||
|
import { ProjectService } from "../../sys/enterprise/service/project-service.js";
|
||||||
|
|
||||||
@Provide()
|
@Provide()
|
||||||
@Scope(ScopeEnum.Request, {allowDowngrade: true})
|
@Scope(ScopeEnum.Request, {allowDowngrade: true})
|
||||||
@@ -44,6 +46,10 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
|||||||
@Inject()
|
@Inject()
|
||||||
jobHistoryService: JobHistoryService;
|
jobHistoryService: JobHistoryService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
userService: UserService;
|
||||||
|
@Inject()
|
||||||
|
projectService: ProjectService;
|
||||||
|
|
||||||
@Inject()
|
@Inject()
|
||||||
cron: Cron;
|
cron: Cron;
|
||||||
@@ -353,18 +359,7 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async checkAllByUsers(userId: any,projectId?: number) {
|
async checkList(sites: SiteInfoEntity[]) {
|
||||||
if (userId==null) {
|
|
||||||
throw new Error("userId is required");
|
|
||||||
}
|
|
||||||
// const sites = await this.repository.find({
|
|
||||||
// where: {userId,projectId}
|
|
||||||
// });
|
|
||||||
// this.checkList(sites,false);
|
|
||||||
await this.triggerJobOnce(userId,projectId);
|
|
||||||
}
|
|
||||||
|
|
||||||
async checkList(sites: SiteInfoEntity[],isCommon: boolean) {
|
|
||||||
const cache = {}
|
const cache = {}
|
||||||
const getFromCache = async (userId: number,projectId?: number) =>{
|
const getFromCache = async (userId: number,projectId?: number) =>{
|
||||||
const key = `${userId}_${projectId??""}`
|
const key = `${userId}_${projectId??""}`
|
||||||
@@ -377,13 +372,6 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
|||||||
}
|
}
|
||||||
for (const site of sites) {
|
for (const site of sites) {
|
||||||
const setting = await getFromCache(site.userId,site.projectId)
|
const setting = await getFromCache(site.userId,site.projectId)
|
||||||
if (isCommon) {
|
|
||||||
//公共的检查,排除有设置cron的用户
|
|
||||||
if (setting?.cron) {
|
|
||||||
//设置了cron,跳过公共检查
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let retryTimes = setting?.retryTimes
|
let retryTimes = setting?.retryTimes
|
||||||
this.doCheck(site,true,retryTimes).catch(e => {
|
this.doCheck(site,true,retryTimes).catch(e => {
|
||||||
logger.error(`检查站点证书失败,${site.domain}`, e.message);
|
logger.error(`检查站点证书失败,${site.domain}`, e.message);
|
||||||
@@ -492,57 +480,73 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async registerSiteMonitorJob(userId?: number,projectId?: number) {
|
async registerSiteMonitorJob(userId?: number,projectId?: number) {
|
||||||
|
const setting = await this.userSettingsService.getSetting<UserSiteMonitorSetting>(userId,projectId, UserSiteMonitorSetting);
|
||||||
|
if (!setting.cron) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//注册个人的 或项目的
|
||||||
|
this.cron.register({
|
||||||
|
name: `siteMonitor_${userId}_${projectId||""}`,
|
||||||
|
cron: setting.cron,
|
||||||
|
job: () => this.triggerJobOnce(userId,projectId),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if(userId == null){
|
async triggerCommonJob(){
|
||||||
//注册公共job
|
//遍历用户
|
||||||
logger.info(`注册站点证书检查定时任务`)
|
const userIds = await this.userService.getAllUserIds()
|
||||||
this.cron.register({
|
for (const userId of userIds) {
|
||||||
name: 'siteMonitor',
|
const setting = await this.userSettingsService.getSetting<UserSiteMonitorSetting>(userId,null,UserSiteMonitorSetting)
|
||||||
cron: '0 0 0 * * *',
|
if(setting && setting.cron){
|
||||||
job:async ()=>{
|
//该用户有自定义检查时间,跳过公共job
|
||||||
await this.triggerJobOnce()
|
continue
|
||||||
},
|
|
||||||
});
|
|
||||||
logger.info(`注册站点证书检查定时任务完成`)
|
|
||||||
}else{
|
|
||||||
const setting = await this.userSettingsService.getSetting<UserSiteMonitorSetting>(userId,projectId, UserSiteMonitorSetting);
|
|
||||||
if (!setting.cron) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
//注册个人的 或项目的
|
await this.triggerJobOnce(userId)
|
||||||
this.cron.register({
|
|
||||||
name: `siteMonitor_${userId}_${projectId||""}`,
|
|
||||||
cron: setting.cron,
|
|
||||||
job: () => this.triggerJobOnce(userId,projectId),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//遍历项目
|
||||||
|
const projectIds = await this.projectService.getAllProjectIds()
|
||||||
|
for (const projectId of projectIds) {
|
||||||
|
const userId = Constants.enterpriseUserId
|
||||||
|
const setting = await this.userSettingsService.getSetting<UserSiteMonitorSetting>(userId,projectId,UserSiteMonitorSetting)
|
||||||
|
if(setting && setting.cron){
|
||||||
|
//该项目有自定义检查时间,跳过公共job
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
await this.triggerJobOnce(userId,projectId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async triggerJobOnce(userId?:number,projectId?:number) {
|
async triggerJobOnce(userId?:number,projectId?:number) {
|
||||||
logger.info(`站点证书检查开始执行[${userId??'所有用户'}_${projectId??'所有项目'}]`);
|
if(userId==null){
|
||||||
const query:any = { disabled: false };
|
throw new Error("userId is required");
|
||||||
let jobEntity :Partial<JobHistoryEntity> = null;
|
|
||||||
if(userId!=null){
|
|
||||||
query.userId = userId;
|
|
||||||
if(projectId){
|
|
||||||
query.projectId = projectId;
|
|
||||||
}
|
|
||||||
//判断是否已关闭
|
|
||||||
const setting = await this.userSettingsService.getSetting<UserSiteMonitorSetting>(userId,projectId, UserSiteMonitorSetting);
|
|
||||||
if (setting && !setting.cron) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
jobEntity = {
|
|
||||||
userId,
|
|
||||||
projectId,
|
|
||||||
type:"siteCertMonitor",
|
|
||||||
title: '站点证书检查',
|
|
||||||
result:"start",
|
|
||||||
startAt:new Date().getTime(),
|
|
||||||
}
|
|
||||||
await this.jobHistoryService.add(jobEntity);
|
|
||||||
}
|
}
|
||||||
|
const query:any = { disabled: false };
|
||||||
|
query.userId = userId;
|
||||||
|
if(projectId){
|
||||||
|
query.projectId = projectId;
|
||||||
|
}
|
||||||
|
const siteCount = await this.repository.count({
|
||||||
|
where: query,
|
||||||
|
});
|
||||||
|
if (siteCount === 0) {
|
||||||
|
logger.info(`用户/项目[${userId}_${projectId||""}]没有站点证书需要检查`)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info(`站点证书检查开始执行[${userId}_${projectId||""}]`);
|
||||||
|
|
||||||
|
let jobEntity :Partial<JobHistoryEntity> = null;
|
||||||
|
|
||||||
|
jobEntity = {
|
||||||
|
userId,
|
||||||
|
projectId,
|
||||||
|
type:"siteCertMonitor",
|
||||||
|
title: '站点证书检查',
|
||||||
|
result:"start",
|
||||||
|
startAt:new Date().getTime(),
|
||||||
|
}
|
||||||
|
await this.jobHistoryService.add(jobEntity);
|
||||||
let offset = 0;
|
let offset = 0;
|
||||||
const limit = 50;
|
const limit = 50;
|
||||||
let count = 0;
|
let count = 0;
|
||||||
@@ -557,21 +561,18 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
offset += records.length;
|
offset += records.length;
|
||||||
const isCommon = !userId;
|
|
||||||
count += records.length;
|
count += records.length;
|
||||||
await this.checkList(records,isCommon);
|
await this.checkList(records);
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info(`站点证书检查完成[${userId??'所有用户'}_${projectId??'所有项目'}]`);
|
logger.info(`站点证书检查完成[${userId}_${projectId||""}]`);
|
||||||
if(jobEntity){
|
await this.jobHistoryService.update({
|
||||||
await this.jobHistoryService.update({
|
id: jobEntity.id,
|
||||||
id: jobEntity.id,
|
result: "done",
|
||||||
result: "done",
|
content:`共检查${count}个站点`,
|
||||||
content:`共检查${count}个站点`,
|
endAt:new Date().getTime(),
|
||||||
endAt:new Date().getTime(),
|
updateTime:new Date(),
|
||||||
updateTime:new Date(),
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async batchDelete(ids: number[], userId: number,projectId?:number): Promise<void> {
|
async batchDelete(ids: number[], userId: number,projectId?:number): Promise<void> {
|
||||||
|
|||||||
@@ -320,8 +320,6 @@ export class SiteIpService extends BaseService<SiteIpEntity> {
|
|||||||
for (const item of list) {
|
for (const item of list) {
|
||||||
await this.add(item);
|
await this.add(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
// await this.checkAllByUsers(req.userId);
|
|
||||||
};
|
};
|
||||||
await batchAdd(list);
|
await batchAdd(list);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -400,7 +400,15 @@ export class UserService extends BaseService<UserEntity> {
|
|||||||
id: userId,
|
id: userId,
|
||||||
...body,
|
...body,
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAllUserIds() {
|
||||||
|
const users = await this.repository.find({
|
||||||
|
select: ['id'],
|
||||||
|
where: {
|
||||||
|
status: 1,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return users.map(item => item.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -284,4 +284,14 @@ export class ProjectService extends BaseService<ProjectEntity> {
|
|||||||
return project?.isSystem ?? false;
|
return project?.isSystem ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async getAllProjectIds() {
|
||||||
|
const projects = await this.repository.find({
|
||||||
|
select: ['id'],
|
||||||
|
where: {
|
||||||
|
disabled: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return projects.map(item => item.id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user