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