Files
wwjcloud-nest-v1/wwjcloud-nest-v1/EMERGENCY_FIXES_UPDATED.md
wanwu 6eb9ea687d feat: 初始化项目代码
- 迁移 NestJS 项目结构
- 添加 uniappx 前端代码
- 配置数据库连接
- 添加核心业务模块
2026-04-02 21:25:02 +08:00

597 lines
19 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 🚨 NestJS v1 Boot层基础能力紧急修复方案基于现有框架能力
## 📋 修复优先级与影响评估
| 优先级 | 问题 | 业务影响 | 技术风险 | 预计工时 |
|--------|------|----------|----------|----------|
| 🔴 **P0-紧急** | 数据库连接池监控缺失 | 生产性能调优盲区 | 高 | 2小时 |
| 🔴 **P0-紧急** | 事务边界不完整 | 数据一致性风险 | 高 | 4小时 |
| 🟡 **P1-重要** | 缓存命名空间治理优化 | 运维效率降低 | 中 | 2小时 |
| 🟡 **P1-重要** | 查询构建器工具增强 | 开发效率影响 | 中 | 3小时 |
---
## 🔍 现有框架能力分析
### ✅ 已具备的能力
1. **配置验证体系**完整的Joi验证框架 (`validation.ts`)
2. **缓存基础设施**CacheManagerService支持标签和分组 (`cache-manager.service.ts`)
3. **监控指标**Prometheus集成支持HTTP和AI事件监控 (`metrics.service.ts`)
4. **健康检查**内存、磁盘、HTTP外部依赖检查 (`health.controller.ts`)
5. **事务支持**SQLScriptRunnerTools提供QueryRunner事务封装
6. **应用配置**AppConfigService统一管理环境变量
### ❌ 缺失的关键能力
1. **数据库连接池参数暴露**TypeORM配置缺少连接池监控
2. **事务装饰器**:缺少@Transactional注解支持
3. **缓存命中率监控**CacheManagerService缺少命中率统计
4. **查询构建工具**缺少类似Java QueryMapperUtils的工具类
---
## 🔴 P0-紧急修复项
### 1. 数据库连接池监控修复(利用现有配置体系)
**问题描述**
- Java使用Druid提供完整连接池参数配置
- NestJS v1 TypeORM连接池参数未暴露缺少监控指标
**修复方案**基于现有validation.ts配置
```typescript
// 文件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
```typescript
// 文件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
```typescript
// 文件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 事务装饰器(基于现有基础设施)
```typescript
// 文件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 支付服务事务加固(基于现有模式)
```typescript
// 文件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
```typescript
// 文件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缺少等价的查询构建工具
**修复方案**(遵循现有工具类模式):
```typescript
// 文件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检查
```bash
# 检查新增配置项
grep "DB_POOL" .env
# 验证健康检查端点
curl http://localhost:3000/health
# 验证Prometheus指标扩展现有指标
curl http://localhost:3000/metrics | grep wwjcloud_
```
### 2. 事务验证(基于现有测试模式)
```typescript
// 文件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
```bash
# 验证缓存命中率(扩展指标)
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 | 现有测试框架 |
---
## 🎯 验收标准(基于现有能力)
### ✅ 必须满足的条件
1. **数据库监控**
- ✅ 新增配置项通过validation.ts验证
- ✅ 连接池参数可通过环境变量配置
- ✅ 扩展现有MetricsService支持数据库指标
2. **事务完整性**
- ✅ 基于现有QueryRunner实现事务装饰器
- ✅ 支付退款、会员账户更新使用事务装饰器
- ✅ 事务失败时能正确回滚所有操作
3. **缓存治理**
- ✅ 基于现有CacheManagerService扩展命中率统计
- ✅ 利用现有标签系统实现命名空间清理
- ✅ 清理操作不影响其他命名空间数据
4. **查询工具**
- ✅ 支持时间范围、模糊搜索、排序、分页
- ✅ 对齐Java QueryMapperUtils功能
- ✅ 遵循现有工具类设计模式
### 🚫 阻断条件
- 任何修复导致现有功能异常
- 性能下降超过10%
- 与现有框架能力冲突
---
## 🔧 技术实现要点
### 1. 配置集成原则
- 所有新增配置必须通过`validation.ts`验证
- 使用现有`AppConfigService`模式获取配置
- 遵循"不设置默认值"原则,默认值在具体实现中兜底
### 2. 监控集成原则
- 扩展现有`MetricsService`,不重复创建新服务
- 利用现有事件总线`EventBus`进行模块状态通知
- 遵循现有Prometheus指标命名规范
### 3. 事务实现原则
- 基于现有`SQLScriptRunnerTools`的QueryRunner模式
- 保持与Java `@Transactional`注解的语义一致性
- 支持传播行为和隔离级别配置
### 4. 缓存优化原则
- 基于现有`CacheManagerService`进行扩展
- 利用现有标签系统实现命名空间功能
- 保持与Redis的兼容性
---
## 📞 紧急联系方式
- **技术负责人**:后端架构师
- **产品负责人**:产品经理
- **运维负责人**:运维工程师
- **QA负责人**:测试经理
**修复完成后需立即通知所有相关方进行验收测试!**
---
## 📝 版本说明
**本文档基于现有Boot层框架能力分析所有修复方案均建立在已有基础设施之上确保**
1. ✅ 不引入与现有框架冲突的新依赖
2. ✅ 充分利用已验证的框架能力
3. ✅ 保持与Java实现的语义一致性
4. ✅ 最小化代码变更和风险
**最后更新**基于Boot层框架能力审查后修订