mirror of
https://github.com/certd/certd.git
synced 2026-04-23 19:57:27 +08:00
perf: 优化站点证书检查页面,检查增加3次重试
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { Autoload, Config, Init, Inject, Scope, ScopeEnum } from '@midwayjs/core';
|
||||
import { PipelineService } from '../pipeline/service/pipeline-service.js';
|
||||
import { logger } from '@certd/basic';
|
||||
import { logger, utils } from '@certd/basic';
|
||||
import { SysSettingsService } from '@certd/lib-server';
|
||||
import { SiteInfoService } from '../monitor/index.js';
|
||||
import { Cron } from '../cron/cron.js';
|
||||
@@ -59,13 +59,7 @@ export class AutoCRegisterCron {
|
||||
break;
|
||||
}
|
||||
offset += records.length;
|
||||
for (const record of records) {
|
||||
try {
|
||||
await this.siteInfoService.doCheck(record, true);
|
||||
} catch (e) {
|
||||
logger.error(`站点${record.name}检查出错:`, e);
|
||||
}
|
||||
}
|
||||
await this.siteInfoService.checkList(records);
|
||||
}
|
||||
|
||||
logger.info('站点证书检查完成');
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Repository } from 'typeorm';
|
||||
import { SiteInfoEntity } from '../entity/site-info.js';
|
||||
import { siteTester } from './site-tester.js';
|
||||
import dayjs from 'dayjs';
|
||||
import { logger } from '@certd/basic';
|
||||
import { logger, utils } from '@certd/basic';
|
||||
import { PeerCertificate } from 'tls';
|
||||
import { NotificationService } from '../../pipeline/service/notification-service.js';
|
||||
import { isComm, isPlus } from '@certd/plus-core';
|
||||
@@ -76,23 +76,35 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
||||
* 检查站点证书过期时间
|
||||
* @param site
|
||||
* @param notify
|
||||
* @param retryTimes
|
||||
*/
|
||||
async doCheck(site: SiteInfoEntity, notify = true) {
|
||||
async doCheck(site: SiteInfoEntity, notify = true, retryTimes = 3) {
|
||||
if (!site?.domain) {
|
||||
throw new Error('站点域名不能为空');
|
||||
}
|
||||
try {
|
||||
await this.update({
|
||||
id: site.id,
|
||||
checkStatus: 'checking',
|
||||
lastCheckTime: dayjs,
|
||||
});
|
||||
const res = await siteTester.test({
|
||||
host: site.domain,
|
||||
port: site.httpsPort,
|
||||
retryTimes,
|
||||
});
|
||||
|
||||
const certi: PeerCertificate = res.certificate;
|
||||
if (!certi) {
|
||||
return;
|
||||
throw new Error('没有发现证书');
|
||||
}
|
||||
const expires = certi.valid_to;
|
||||
const domains = [certi.subject?.CN, ...certi.subjectaltname?.replaceAll('DNS:', '').split(',')];
|
||||
const allDomains = certi.subjectaltname?.replaceAll('DNS:', '').split(',');
|
||||
const mainDomain = certi.subject?.CN;
|
||||
let domains = allDomains;
|
||||
if (!allDomains.includes(mainDomain)) {
|
||||
domains = [mainDomain, ...allDomains];
|
||||
}
|
||||
const issuer = `${certi.issuer.O}<${certi.issuer.CN}>`;
|
||||
const isExpired = dayjs().valueOf() > dayjs(expires).valueOf();
|
||||
const status = isExpired ? 'expired' : 'ok';
|
||||
@@ -139,13 +151,14 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
||||
* 检查,但不发邮件
|
||||
* @param id
|
||||
* @param notify
|
||||
* @param retryTimes
|
||||
*/
|
||||
async check(id: number, notify = false) {
|
||||
async check(id: number, notify = false, retryTimes = 3) {
|
||||
const site = await this.info(id);
|
||||
if (!site) {
|
||||
throw new Error('站点不存在');
|
||||
}
|
||||
return await this.doCheck(site, notify);
|
||||
return await this.doCheck(site, notify, retryTimes);
|
||||
}
|
||||
|
||||
async sendCheckErrorNotify(site: SiteInfoEntity) {
|
||||
@@ -206,15 +219,22 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
|
||||
}
|
||||
}
|
||||
|
||||
async checkAll(userId: any) {
|
||||
async checkAllByUsers(userId: any) {
|
||||
if (!userId) {
|
||||
throw new Error('userId is required');
|
||||
}
|
||||
const sites = await this.repository.find({
|
||||
where: { userId },
|
||||
});
|
||||
this.checkList(sites);
|
||||
}
|
||||
|
||||
async checkList(sites: SiteInfoEntity[]) {
|
||||
for (const site of sites) {
|
||||
await this.doCheck(site);
|
||||
this.doCheck(site).catch(e => {
|
||||
logger.error(`检查站点证书失败,${site.domain}`, e.message);
|
||||
});
|
||||
await utils.sleep(200);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { logger } from '@certd/basic';
|
||||
import { logger, utils } from '@certd/basic';
|
||||
import { merge } from 'lodash-es';
|
||||
import https from 'https';
|
||||
import { PeerCertificate } from 'tls';
|
||||
@@ -6,6 +6,7 @@ export type SiteTestReq = {
|
||||
host: string; // 只用域名部分
|
||||
port?: number;
|
||||
method?: string;
|
||||
retryTimes?: number;
|
||||
};
|
||||
|
||||
export type SiteTestRes = {
|
||||
@@ -14,6 +15,28 @@ export type SiteTestRes = {
|
||||
export class SiteTester {
|
||||
async test(req: SiteTestReq): Promise<SiteTestRes> {
|
||||
logger.info('测试站点:', JSON.stringify(req));
|
||||
const maxRetryTimes = req.retryTimes ?? 3;
|
||||
let tryCount = 0;
|
||||
let result: SiteTestRes = {};
|
||||
while (true) {
|
||||
try {
|
||||
result = await this.doTestOnce(req);
|
||||
return result;
|
||||
} catch (e) {
|
||||
tryCount++;
|
||||
if (tryCount > maxRetryTimes) {
|
||||
logger.error(`测试站点出错,重试${maxRetryTimes}次`, e);
|
||||
throw e;
|
||||
}
|
||||
//指数退避
|
||||
const time = 2 ** tryCount;
|
||||
logger.error(`测试站点出错,${time}s后重试`, e);
|
||||
await utils.sleep(time * 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async doTestOnce(req: SiteTestReq): Promise<SiteTestRes> {
|
||||
const agent = new https.Agent({ keepAlive: false });
|
||||
|
||||
const options: any = merge(
|
||||
|
||||
Reference in New Issue
Block a user