# 定时任务执行范围优化 - 总结
**日期**: 2026-05-13
**状态**: ✅ 完成并编译通过
---
## 🎯 问题分析
定时任务应该处理**订单表中有标签的数据**,但之前的实现只处理:
1. ❌ 缓存表中status=0(待处理)的记录
2. ❌ 缓存表中status=2(失败)且未超过重试次数的记录
**漏洞**:订单表中**新增的有标签订单**如果不在缓存表中,就永远不会被处理。
---
## ✅ 改进方案
现在定时任务按以下优先级处理:
```
第一步:处理失效的缓存(Status=3)
└─ 订单表中有对应的有标签订单
第二步:处理待处理的任务(Status=0或2)
└─ 订单表中有对应的有标签订单
第三步:处理订单表中新的有标签订单 ⭐ 新增
└─ 缓存表中不存在对应记录
└─ 订单表中该订单有标签数据
```
---
## 🔧 代码修改
### 1. 新增Repository方法
**文件**: `LabelPdfCacheRepository.cs`
```csharp
///
/// 获取订单表中新的有标签订单(缓存表中不存在的)
///
public async Task> GetNewOrdersWithLabelsAsync(int limit)
{
var db = _provider.GetClient();
return await db.Queryable()
.Where(o => !string.IsNullOrEmpty(o.Label)) // 订单有标签
.Where(o => !SqlFunc.Subqueryable()
.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()
.Where(c => c.NeutralWaybillNumber == o.NeutralWaybillNumber)
.Any()) // 确保缓存表中不存在
```
3. **批量处理限制**
- batchSize控制单次处理数量
- 防止定时任务过度执行
4. **完整的日志记录**
- 记录各阶段处理数量
- 便于监控和调试
---
## ✨ 现在的覆盖场景
| 场景 | 处理方式 | 结果 |
|------|--------|------|
| 新订单有标签 | 第三步 | ✅ 立即创建缓存 |
| 已缓存订单 | 第一、二步 | ✅ 重试或更新 |
| 订单无标签 | 过滤掉 | ✅ 跳过 |
| 缓存表无记录 | 第三步 | ✅ 创建新记录 |
---
## 📈 预期收益
1. **完整覆盖** ✅
- 不再有漏掉的新订单
- 所有有标签订单都会被处理
2. **及时处理** ✅
- 新订单会在下个定时任务周期处理
- 缩短缓存生成时间
3. **可观测性** ✅
- 详细的执行日志
- 清晰的处理数量统计
4. **性能平衡** ✅
- batchSize限制单次处理量
- 不会过度消耗资源
---
## 📝 编译验证
```
✅ 编译成功(exit code = 0)
✅ 零编译错误
✅ 新增方法已实现
✅ 接口已更新
✅ 逻辑已完善
```
---
## 🚀 现在的定时任务能够
1. ✅ 处理订单表中**所有有标签的订单**
2. ✅ 优先处理失效和待处理的缓存
3. ✅ 自动发现新的有标签订单
4. ✅ 为新订单创建缓存记录
5. ✅ 提供详细的执行日志
---
**任务完成!定时任务现在能够正确处理订单表中所有有标签的数据。** ✅