19 KiB
19 KiB
🚨 NestJS v1 Boot层基础能力紧急修复方案(基于现有框架能力)
📋 修复优先级与影响评估
| 优先级 | 问题 | 业务影响 | 技术风险 | 预计工时 |
|---|---|---|---|---|
| 🔴 P0-紧急 | 数据库连接池监控缺失 | 生产性能调优盲区 | 高 | 2小时 |
| 🔴 P0-紧急 | 事务边界不完整 | 数据一致性风险 | 高 | 4小时 |
| 🟡 P1-重要 | 缓存命名空间治理优化 | 运维效率降低 | 中 | 2小时 |
| 🟡 P1-重要 | 查询构建器工具增强 | 开发效率影响 | 中 | 3小时 |
🔍 现有框架能力分析
✅ 已具备的能力
- 配置验证体系:完整的Joi验证框架 (
validation.ts) - 缓存基础设施:CacheManagerService支持标签和分组 (
cache-manager.service.ts) - 监控指标:Prometheus集成,支持HTTP和AI事件监控 (
metrics.service.ts) - 健康检查:内存、磁盘、HTTP外部依赖检查 (
health.controller.ts) - 事务支持:SQLScriptRunnerTools提供QueryRunner事务封装
- 应用配置:AppConfigService统一管理环境变量
❌ 缺失的关键能力
- 数据库连接池参数暴露:TypeORM配置缺少连接池监控
- 事务装饰器:缺少@Transactional注解支持
- 缓存命中率监控:CacheManagerService缺少命中率统计
- 查询构建工具:缺少类似Java QueryMapperUtils的工具类
🔴 P0-紧急修复项
1. 数据库连接池监控修复(利用现有配置体系)
问题描述:
- Java使用Druid提供完整连接池参数配置
- NestJS v1 TypeORM连接池参数未暴露,缺少监控指标
修复方案(基于现有validation.ts配置):
// 文件:libs/wwjcloud-boot/src/config/validation.ts - 新增配置项
export const validationSchema = Joi.object({
// ... 现有配置 ...
// 数据库连接池配置(新增)
DB_POOL_MAX: Joi.number().optional(),
DB_POOL_MIN: Joi.number().optional(),
DB_POOL_ACQUIRE_TIMEOUT: Joi.number().optional(),
DB_POOL_TIMEOUT: Joi.number().optional(),
DB_POOL_IDLE_TIMEOUT: Joi.number().optional(),
DB_POOL_MAX_USES: Joi.number().optional(),
// 慢查询监控(新增)
DB_SLOW_QUERY_THRESHOLD: Joi.number().optional(),
DB_MAX_QUERY_TIME: Joi.number().optional(),
DB_QUERY_LOG_ENABLED: Joi.boolean().optional(),
});
TypeORM配置增强(基于现有AppConfigService):
// 文件:libs/wwjcloud-core/src/app.module.ts
TypeOrmModule.forRootAsync({
useFactory: (configService: ConfigService) => ({
type: 'mysql',
host: process.env.DB_HOST,
port: Number(process.env.DB_PORT),
username: process.env.DB_USERNAME,
password: process.env.DB_PASSWORD,
database: process.env.DB_DATABASE,
synchronize: process.env.DB_SYNCHRONIZE === 'true',
// 🔧 基于现有配置体系新增连接池配置
extra: {
connectionLimit: Number(process.env.DB_POOL_MAX) || 10,
acquireTimeout: Number(process.env.DB_POOL_ACQUIRE_TIMEOUT) || 60000,
timeout: Number(process.env.DB_POOL_TIMEOUT) || 60000,
idleTimeout: Number(process.env.DB_POOL_IDLE_TIMEOUT) || 600000,
maxUses: Number(process.env.DB_POOL_MAX_USES) || 0,
},
// 🔧 基于现有MetricsService新增监控
logger: 'advanced-console',
maxQueryExecutionTime: Number(process.env.DB_MAX_QUERY_TIME) || 5000,
logging: process.env.DB_QUERY_LOG_ENABLED === 'true' ? ['query', 'error'] : ['error'],
}),
})
数据库监控指标(扩展现有MetricsService):
// 文件:libs/wwjcloud-boot/src/infra/metrics/database-metrics.service.ts
import { Injectable } from '@nestjs/common';
import { MetricsService } from './metrics.service';
@Injectable()
export class DatabaseMetricsService {
constructor(private readonly metricsService: MetricsService) {}
// 🔧 扩展现有指标系统
recordQueryDuration(duration: number, queryType: string, table: string) {
if (this.metricsService.isEnabled()) {
// 复用现有HTTP指标模式,扩展为数据库指标
this.metricsService.observeRequest('QUERY', table, 200, duration);
}
}
// 🔧 连接池状态监控
updateConnectionPoolMetrics(poolStats: any) {
if (this.metricsService.isEnabled()) {
this.metricsService.observeAiEvent('db_connection_pool', 'info', JSON.stringify(poolStats));
}
}
}
2. 事务边界完整性修复(基于现有QueryRunner)
问题描述:
- Java在服务层广泛使用
@Transactional - NestJS v1仅在关键路径使用显式事务,存在数据一致性风险
修复方案(基于现有SQLScriptRunnerTools):
2.1 事务装饰器(基于现有基础设施)
// 文件:libs/wwjcloud-boot/src/infra/transaction/transactional.decorator.ts
import { Inject, Injectable } from '@nestjs/common';
import { DataSource } from 'typeorm';
export function Transactional() {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = async function (...args: any[]) {
const dataSource = this.dataSource || this.connection;
if (!dataSource) {
throw new Error('DataSource not found for transactional method');
}
const queryRunner = dataSource.createQueryRunner();
try {
await queryRunner.connect();
await queryRunner.startTransaction();
// 🔧 基于现有QueryRunner实现事务
const result = await originalMethod.apply(this, [...args, queryRunner.manager]);
await queryRunner.commitTransaction();
return result;
} catch (error) {
await queryRunner.rollbackTransaction();
throw error;
} finally {
await queryRunner.release();
}
};
};
}
2.2 支付服务事务加固(基于现有模式)
// 文件:libs/wwjcloud-core/src/services/core/pay/impl/core-pay-service-impl.service.ts
import { Transactional } from '@wwjBoot/infra/transaction/transactional.decorator';
export class CorePayServiceImpl {
@Transactional() // 🔧 使用新的事务装饰器
async refund(params: RefundParams, entityManager?: EntityManager): Promise<PayRefund> {
// 🔧 使用传入的entityManager确保事务一致性
const payRepo = entityManager.getRepository(Pay);
const refundRepo = entityManager.getRepository(PayRefund);
const logRepo = entityManager.getRepository(PayRefundLog);
// 1. 检查原支付状态
const originalPay = await payRepo.findOne({
where: { outTradeNo: params.outTradeNo }
});
if (!originalPay || originalPay.status !== PayStatus.PAID) {
throw new BadRequestException('原支付状态异常');
}
// 2. 创建退款记录
const refund = refundRepo.create({
...params,
status: RefundStatus.PROCESSING,
createTime: new Date()
});
const savedRefund = await refundRepo.save(refund);
// 3. 更新原支付状态
await payRepo.update(
{ outTradeNo: params.outTradeNo },
{ status: PayStatus.REFUNDING }
);
// 4. 记录退款日志
await logRepo.save({
refundId: savedRefund.id,
action: 'create_refund',
createTime: new Date()
});
return savedRefund;
}
}
🟡 P1-重要修复项
3. 缓存命名空间治理优化(基于现有CacheManagerService)
问题描述:
- Java使用Cache Tag设计,支持按标签清理
- NestJS v1已有CacheManagerService但缺少命中率统计
修复方案(扩展现有CacheManagerService):
// 文件:libs/wwjcloud-boot/src/infra/cache/cache-manager.service.ts - 扩展现有类
export class CacheManagerService {
private readonly hitCounter = new Map<string, number>();
private readonly missCounter = new Map<string, number>();
async get<T = any>(key: string, namespace?: string): Promise<T | null> {
const actualKey = namespace ? `${namespace}:${key}` : key;
const result = await this.cacheService.get<T>(actualKey);
// 🔧 基于现有架构新增命中率统计
const metricsKey = namespace || 'default';
if (result) {
this.hitCounter.set(metricsKey, (this.hitCounter.get(metricsKey) || 0) + 1);
} else {
this.missCounter.set(metricsKey, (this.missCounter.get(metricsKey) || 0) + 1);
}
return result;
}
// 🔧 新增:基于现有标签系统的命名空间清理
async clearByNamespace(namespace: string): Promise<void> {
// 利用现有的标签系统实现命名空间清理
await this.invalidateByTag(namespace);
}
// 🔧 新增:命中率指标(复用现有MetricsService)
getHitRateMetrics(): Record<string, { hits: number; misses: number; rate: number }> {
const metrics: Record<string, any> = {};
for (const [namespace, hits] of this.hitCounter.entries()) {
const misses = this.missCounter.get(namespace) || 0;
const total = hits + misses;
metrics[namespace] = {
hits,
misses,
rate: total > 0 ? (hits / total) * 100 : 0
};
}
return metrics;
}
}
4. 查询构建器工具增强(基于现有工具类模式)
问题描述:
- Java有
QueryMapperUtils统一封装时间范围、模糊匹配等 - NestJS v1缺少等价的查询构建工具
修复方案(遵循现有工具类模式):
// 文件:libs/wwjcloud-boot/src/vendor/utils/query-builder.utils.ts
import { SelectQueryBuilder } from 'typeorm';
/**
* 查询构建器工具类
* 严格对齐Java: com.niu.core.service.core.app.tools.QueryMapperUtils
*/
export class QueryBuilderUtils {
/**
* 构建时间范围查询条件 - 对齐Java时间范围处理
*/
static buildTimeRange(
queryBuilder: SelectQueryBuilder<any>,
field: string,
startTime?: Date,
endTime?: Date
): SelectQueryBuilder<any> {
if (startTime) {
queryBuilder.andWhere(`${field} >= :startTime`, { startTime });
}
if (endTime) {
// 🔧 对齐Java的结束时间处理(包含当天)
const endTimeInclusive = new Date(endTime);
endTimeInclusive.setHours(23, 59, 59, 999);
queryBuilder.andWhere(`${field} <= :endTime`, { endTime: endTimeInclusive });
}
return queryBuilder;
}
/**
* 构建模糊匹配查询条件 - 对齐Java模糊搜索
*/
static buildFuzzySearch(
queryBuilder: SelectQueryBuilder<any>,
field: string,
keyword?: string,
alias?: string
): SelectQueryBuilder<any> {
if (keyword && keyword.trim()) {
const fieldName = alias ? `${alias}.${field}` : field;
// 🔧 对齐Java的LIKE模式(前后模糊匹配)
queryBuilder.andWhere(`${fieldName} LIKE :keyword`, {
keyword: `%${keyword.trim()}%`
});
}
return queryBuilder;
}
/**
* 构建多字段模糊匹配 - 对齐Java多字段搜索
*/
static buildMultiFieldSearch(
queryBuilder: SelectQueryBuilder<any>,
fields: Array<{ field: string; alias?: string }>,
keyword?: string
): SelectQueryBuilder<any> {
if (keyword && keyword.trim()) {
const conditions = fields.map(({ field, alias }) => {
const fieldName = alias ? `${alias}.${field}` : field;
return `${fieldName} LIKE :keyword`;
}).join(' OR ');
queryBuilder.andWhere(`(${conditions})`, {
keyword: `%${keyword.trim()}%`
});
}
return queryBuilder;
}
/**
* 构建排序条件 - 对齐Java排序规则
*/
static buildOrderBy(
queryBuilder: SelectQueryBuilder<any>,
sortField?: string,
sortOrder: 'ASC' | 'DESC' = 'DESC',
defaultField = 'createTime'
): SelectQueryBuilder<any> {
const orderField = sortField || defaultField;
// 🔧 对齐Java的安全字段验证
const allowedFields = ['createTime', 'updateTime', 'id', 'sort'];
if (!allowedFields.includes(orderField)) {
throw new Error(`Invalid order field: ${orderField}`);
}
queryBuilder.orderBy(orderField, sortOrder);
return queryBuilder;
}
/**
* 构建分页条件 - 对齐Java分页参数
*/
static buildPagination(
queryBuilder: SelectQueryBuilder<any>,
page: number,
limit: number
): SelectQueryBuilder<any> {
// 🔧 对齐Java的分页参数验证
const validPage = Math.max(1, page);
const validLimit = Math.min(Math.max(1, limit), 100); // 最大100条
const offset = (validPage - 1) * validLimit;
return queryBuilder.skip(offset).take(validLimit);
}
/**
* 完整查询构建器(整合所有功能)- 对齐Java复杂查询
*/
static buildComplexQuery(
queryBuilder: SelectQueryBuilder<any>,
options: {
timeRange?: { field: string; startTime?: Date; endTime?: Date };
fuzzySearch?: Array<{ field: string; keyword?: string; alias?: string }>;
orderBy?: { field?: string; order?: 'ASC' | 'DESC'; defaultField?: string };
pagination?: { page: number; limit: number };
}
): SelectQueryBuilder<any> {
let qb = queryBuilder;
// 时间范围
if (options.timeRange) {
qb = this.buildTimeRange(
qb,
options.timeRange.field,
options.timeRange.startTime,
options.timeRange.endTime
);
}
// 模糊搜索
if (options.fuzzySearch && options.fuzzySearch.length > 0) {
const searchFields = options.fuzzySearch.filter(item => item.keyword && item.keyword.trim());
if (searchFields.length > 0) {
qb = this.buildMultiFieldSearch(
qb,
searchFields.map(item => ({ field: item.field, alias: item.alias })),
searchFields[0].keyword
);
}
}
// 排序
if (options.orderBy) {
qb = this.buildOrderBy(
qb,
options.orderBy.field,
options.orderBy.order,
options.orderBy.defaultField
);
}
// 分页
if (options.pagination) {
qb = this.buildPagination(qb, options.pagination.page, options.pagination.limit);
}
return qb;
}
}
📊 修复验证方案(基于现有框架)
1. 数据库监控验证(利用现有Health检查)
# 检查新增配置项
grep "DB_POOL" .env
# 验证健康检查端点
curl http://localhost:3000/health
# 验证Prometheus指标(扩展现有指标)
curl http://localhost:3000/metrics | grep wwjcloud_
2. 事务验证(基于现有测试模式)
// 文件:libs/wwjcloud-core/src/services/core/pay/__tests__/core-pay-service-impl.spec.ts
import { DataSource } from 'typeorm';
describe('CorePayServiceImpl - Transaction', () => {
let dataSource: DataSource;
beforeEach(() => {
dataSource = app.get(DataSource);
});
it('should rollback transaction on error', async () => {
// 🔧 基于现有QueryRunner测试事务回滚
const queryRunner = dataSource.createQueryRunner();
await queryRunner.connect();
await queryRunner.startTransaction();
try {
// 模拟支付退款失败
await payService.refund({ outTradeNo: 'invalid', amount: 100 }, queryRunner.manager);
fail('Should have thrown error');
} catch (error) {
await queryRunner.rollbackTransaction();
// 验证数据一致性
const pay = await queryRunner.manager.findOne(Pay, { outTradeNo: 'invalid' });
expect(pay.status).not.toBe(PayStatus.REFUNDING);
} finally {
await queryRunner.release();
}
});
});
3. 缓存验证(基于现有CacheManagerService)
# 验证缓存命中率(扩展指标)
curl http://localhost:3000/metrics | grep cache_hit_rate
# 测试命名空间清理(基于现有标签系统)
redis-cli KEYS "wwjcloud:site:*" | wc -l
# 执行清理后验证
⏰ 实施计划(基于现有框架)
| 阶段 | 任务 | 负责人 | 开始时间 | 完成时间 | 依赖现有框架 |
|---|---|---|---|---|---|
| 阶段1 | 数据库连接池监控 | 后端开发 | 今天14:00 | 今天16:00 | validation.ts + MetricsService |
| 阶段2 | 事务装饰器实现 | 后端开发 | 今天16:00 | 今天18:00 | SQLScriptRunnerTools模式 |
| 阶段3 | 缓存命名空间优化 | 后端开发 | 明天09:00 | 明天11:00 | CacheManagerService扩展 |
| 阶段4 | 查询构建器工具 | 后端开发 | 明天11:00 | 明天14:00 | 现有工具类模式 |
| 阶段5 | 集成测试与验证 | QA团队 | 明天14:00 | 明天17:00 | 现有测试框架 |
🎯 验收标准(基于现有能力)
✅ 必须满足的条件
-
数据库监控:
- ✅ 新增配置项通过validation.ts验证
- ✅ 连接池参数可通过环境变量配置
- ✅ 扩展现有MetricsService支持数据库指标
-
事务完整性:
- ✅ 基于现有QueryRunner实现事务装饰器
- ✅ 支付退款、会员账户更新使用事务装饰器
- ✅ 事务失败时能正确回滚所有操作
-
缓存治理:
- ✅ 基于现有CacheManagerService扩展命中率统计
- ✅ 利用现有标签系统实现命名空间清理
- ✅ 清理操作不影响其他命名空间数据
-
查询工具:
- ✅ 支持时间范围、模糊搜索、排序、分页
- ✅ 对齐Java QueryMapperUtils功能
- ✅ 遵循现有工具类设计模式
🚫 阻断条件
- 任何修复导致现有功能异常
- 性能下降超过10%
- 与现有框架能力冲突
🔧 技术实现要点
1. 配置集成原则
- 所有新增配置必须通过
validation.ts验证 - 使用现有
AppConfigService模式获取配置 - 遵循"不设置默认值"原则,默认值在具体实现中兜底
2. 监控集成原则
- 扩展现有
MetricsService,不重复创建新服务 - 利用现有事件总线
EventBus进行模块状态通知 - 遵循现有Prometheus指标命名规范
3. 事务实现原则
- 基于现有
SQLScriptRunnerTools的QueryRunner模式 - 保持与Java
@Transactional注解的语义一致性 - 支持传播行为和隔离级别配置
4. 缓存优化原则
- 基于现有
CacheManagerService进行扩展 - 利用现有标签系统实现命名空间功能
- 保持与Redis的兼容性
📞 紧急联系方式
- 技术负责人:后端架构师
- 产品负责人:产品经理
- 运维负责人:运维工程师
- QA负责人:测试经理
修复完成后需立即通知所有相关方进行验收测试!
📝 版本说明
本文档基于现有Boot层框架能力分析,所有修复方案均建立在已有基础设施之上,确保:
- ✅ 不引入与现有框架冲突的新依赖
- ✅ 充分利用已验证的框架能力
- ✅ 保持与Java实现的语义一致性
- ✅ 最小化代码变更和风险
最后更新:基于Boot层框架能力审查后修订