上传源代码版本
This commit is contained in:
@@ -0,0 +1,241 @@
|
||||
# 定时任务执行范围优化 - 总结
|
||||
|
||||
**日期**: 2026-05-13
|
||||
**状态**: ✅ 完成并编译通过
|
||||
|
||||
---
|
||||
|
||||
## 🎯 问题分析
|
||||
|
||||
定时任务应该处理**订单表中有标签的数据**,但之前的实现只处理:
|
||||
1. ❌ 缓存表中status=0(待处理)的记录
|
||||
2. ❌ 缓存表中status=2(失败)且未超过重试次数的记录
|
||||
|
||||
**漏洞**:订单表中**新增的有标签订单**如果不在缓存表中,就永远不会被处理。
|
||||
|
||||
---
|
||||
|
||||
## ✅ 改进方案
|
||||
|
||||
现在定时任务按以下优先级处理:
|
||||
|
||||
```
|
||||
第一步:处理失效的缓存(Status=3)
|
||||
└─ 订单表中有对应的有标签订单
|
||||
|
||||
第二步:处理待处理的任务(Status=0或2)
|
||||
└─ 订单表中有对应的有标签订单
|
||||
|
||||
第三步:处理订单表中新的有标签订单 ⭐ 新增
|
||||
└─ 缓存表中不存在对应记录
|
||||
└─ 订单表中该订单有标签数据
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 代码修改
|
||||
|
||||
### 1. 新增Repository方法
|
||||
|
||||
**文件**: `LabelPdfCacheRepository.cs`
|
||||
|
||||
```csharp
|
||||
/// <summary>
|
||||
/// 获取订单表中新的有标签订单(缓存表中不存在的)
|
||||
/// </summary>
|
||||
public async Task<List<string>> GetNewOrdersWithLabelsAsync(int limit)
|
||||
{
|
||||
var db = _provider.GetClient();
|
||||
return await db.Queryable<LabelReplaceEntity>()
|
||||
.Where(o => !string.IsNullOrEmpty(o.Label)) // 订单有标签
|
||||
.Where(o => !SqlFunc.Subqueryable<LabelPdfCache>()
|
||||
.Where(c => c.NeutralWaybillNumber == o.NeutralWaybillNumber)
|
||||
.Any()) // 缓存表中不存在
|
||||
.Select(o => o.NeutralWaybillNumber)
|
||||
.Take(limit)
|
||||
.ToListAsync();
|
||||
}
|
||||
```
|
||||
|
||||
**关键SQL逻辑**:
|
||||
```sql
|
||||
SELECT o.NeutralWaybillNumber
|
||||
FROM LabelReplaceEntity o
|
||||
WHERE o.Label IS NOT NULL AND o.Label != ''
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM label_pdf_cache c
|
||||
WHERE c.NeutralWaybillNumber = o.NeutralWaybillNumber
|
||||
)
|
||||
```
|
||||
|
||||
### 2. 更新接口定义
|
||||
|
||||
**文件**: `ILabelPdfCacheRepository.cs`
|
||||
- 添加 `GetNewOrdersWithLabelsAsync` 方法签名
|
||||
|
||||
### 3. 增强ProcessPendingTasksAsync逻辑
|
||||
|
||||
**文件**: `LabelPdfCacheService.cs`
|
||||
|
||||
新增第三步处理流程:
|
||||
```csharp
|
||||
// 第三步:处理订单表中新的有标签订单
|
||||
var newBatchSize = remainingBatchSize - pendingTasks.Count;
|
||||
if (newBatchSize > 0)
|
||||
{
|
||||
var newOrders = await _cacheRepository.GetNewOrdersWithLabelsAsync(newBatchSize);
|
||||
foreach (var waybillNumber in newOrders)
|
||||
{
|
||||
if (await ProcessSingleCacheTask(waybillNumber))
|
||||
{
|
||||
successCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**改进的日志**:
|
||||
```
|
||||
Completed processing PDF cache tasks,
|
||||
total processed: 45,
|
||||
invalid: 5,
|
||||
pending: 15,
|
||||
new orders: 25
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 执行范围对比
|
||||
|
||||
### 修改前 ❌
|
||||
|
||||
| 订单状态 | 处理范围 |
|
||||
|---------|---------|
|
||||
| 订单有标签 | ❌ 仅处理缓存表中已存在的 |
|
||||
| 新订单有标签 | ❌ **永远不会处理** |
|
||||
| 缓存表无记录 | ❌ 跳过 |
|
||||
|
||||
### 修改后 ✅
|
||||
|
||||
| 订单状态 | 处理范围 |
|
||||
|---------|---------|
|
||||
| 失效缓存有标签 | ✅ 第一步处理 |
|
||||
| 待处理缓存有标签 | ✅ 第二步处理 |
|
||||
| 新订单有标签 | ✅ 第三步处理 |
|
||||
| 缓存表无记录 | ✅ 新增处理 |
|
||||
|
||||
---
|
||||
|
||||
## 💡 工作流程示例
|
||||
|
||||
**场景**:早上10:00定时任务执行,batchSize=100
|
||||
|
||||
```
|
||||
【第一步】处理失效缓存
|
||||
查询:SELECT * FROM label_pdf_cache WHERE Status=3 AND OrderWithLabel LIMIT 100
|
||||
结果:找到5条失效缓存
|
||||
操作:重新处理这5条
|
||||
|
||||
【第二步】处理待处理任务
|
||||
查询:SELECT * FROM label_pdf_cache
|
||||
WHERE (Status=0 OR (Status=2 AND RetryCount<3))
|
||||
AND OrderWithLabel LIMIT 95
|
||||
结果:找到15条待处理
|
||||
操作:继续处理这15条
|
||||
|
||||
【第三步】处理新订单 ⭐ 新增
|
||||
查询:SELECT o.NeutralWaybillNumber FROM LabelReplaceEntity o
|
||||
WHERE o.Label IS NOT NULL
|
||||
AND NOT EXISTS (SELECT 1 FROM label_pdf_cache c
|
||||
WHERE c.NeutralWaybillNumber = o.NeutralWaybillNumber)
|
||||
LIMIT 80
|
||||
结果:找到25条新订单有标签
|
||||
操作:为这25条新订单创建缓存
|
||||
|
||||
【结果】
|
||||
本次执行处理了 45 条记录
|
||||
- 失效缓存:5条
|
||||
- 待处理任务:15条
|
||||
- 新订单:25条
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🛡️ 防护机制
|
||||
|
||||
1. **订单标签有效性检查**
|
||||
```csharp
|
||||
.Where(o => !string.IsNullOrEmpty(o.Label)) // 确保Label不为空
|
||||
```
|
||||
|
||||
2. **重复处理防护**
|
||||
```csharp
|
||||
.Where(o => !SqlFunc.Subqueryable<LabelPdfCache>()
|
||||
.Where(c => c.NeutralWaybillNumber == o.NeutralWaybillNumber)
|
||||
.Any()) // 确保缓存表中不存在
|
||||
```
|
||||
|
||||
3. **批量处理限制**
|
||||
- batchSize控制单次处理数量
|
||||
- 防止定时任务过度执行
|
||||
|
||||
4. **完整的日志记录**
|
||||
- 记录各阶段处理数量
|
||||
- 便于监控和调试
|
||||
|
||||
---
|
||||
|
||||
## ✨ 现在的覆盖场景
|
||||
|
||||
| 场景 | 处理方式 | 结果 |
|
||||
|------|--------|------|
|
||||
| 新订单有标签 | 第三步 | ✅ 立即创建缓存 |
|
||||
| 已缓存订单 | 第一、二步 | ✅ 重试或更新 |
|
||||
| 订单无标签 | 过滤掉 | ✅ 跳过 |
|
||||
| 缓存表无记录 | 第三步 | ✅ 创建新记录 |
|
||||
|
||||
---
|
||||
|
||||
## 📈 预期收益
|
||||
|
||||
1. **完整覆盖** ✅
|
||||
- 不再有漏掉的新订单
|
||||
- 所有有标签订单都会被处理
|
||||
|
||||
2. **及时处理** ✅
|
||||
- 新订单会在下个定时任务周期处理
|
||||
- 缩短缓存生成时间
|
||||
|
||||
3. **可观测性** ✅
|
||||
- 详细的执行日志
|
||||
- 清晰的处理数量统计
|
||||
|
||||
4. **性能平衡** ✅
|
||||
- batchSize限制单次处理量
|
||||
- 不会过度消耗资源
|
||||
|
||||
---
|
||||
|
||||
## 📝 编译验证
|
||||
|
||||
```
|
||||
✅ 编译成功(exit code = 0)
|
||||
✅ 零编译错误
|
||||
✅ 新增方法已实现
|
||||
✅ 接口已更新
|
||||
✅ 逻辑已完善
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 现在的定时任务能够
|
||||
|
||||
1. ✅ 处理订单表中**所有有标签的订单**
|
||||
2. ✅ 优先处理失效和待处理的缓存
|
||||
3. ✅ 自动发现新的有标签订单
|
||||
4. ✅ 为新订单创建缓存记录
|
||||
5. ✅ 提供详细的执行日志
|
||||
|
||||
---
|
||||
|
||||
**任务完成!定时任务现在能够正确处理订单表中所有有标签的数据。** ✅
|
||||
Reference in New Issue
Block a user