Files
LabelChange-server/.trae/docs/BackgroundTasks/04-Background_Task_Scope_Improvement.md
2026-06-01 16:30:29 +08:00

242 lines
5.9 KiB
Markdown
Raw 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.

# 定时任务执行范围优化 - 总结
**日期**: 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. ✅ 提供详细的执行日志
---
**任务完成!定时任务现在能够正确处理订单表中所有有标签的数据。**