# 定时任务执行范围修改说明 ## 修改内容 ### 修改目标 将定时任务 `ProcessPendingTasksAsync()` 的执行范围限制为仅处理创建时间在 **2026-05-10** 之后的订单。 ### 修改日期 - **修改时间**: 2026-05-14 - **截断日期**: 2026-05-10 00:00:00 --- ## 涉及文件修改 ### 1. LabelReplaceRepository.cs **文件路径**: `src/DAL/Repositories/LabelReplaceRepository.cs` #### 修改的方法: **1.1 GetNewOrdersWithLabelsAsync()** ```csharp public async Task> GetNewOrdersWithLabelsAsync(int limit) { var db = _provider.GetClient(); // 定义截断日期:2026-05-10之后 var cutoffDate = new DateTime(2026, 5, 10, 0, 0, 0); return await db.Queryable() .Where(o => !string.IsNullOrEmpty(o.Label)) .Where(o => o.CreatedAt >= cutoffDate) // 新增 .Where(o => !SqlFunc.Subqueryable() .Where(c => c.NeutralWaybillNumber == o.NeutralWaybillNumber) .Any()) .Select(o => o.NeutralWaybillNumber) .Take(limit) .ToListAsync(); } ``` **说明**: - 添加了 `cutoffDate` 变量定义截断日期 - 添加了 `.Where(o => o.CreatedAt >= cutoffDate)` 条件过滤 - 该方法是定时任务获取新订单的主要入口 **1.2 GetAllOrdersWithLabelsAsync()** ```csharp public async Task> GetAllOrdersWithLabelsAsync(int limit = 1000) { var db = _provider.GetClient(); var cutoffDate = new DateTime(2026, 5, 10, 0, 0, 0); return await db.Queryable() .Where(lr => !string.IsNullOrEmpty(lr.Label)) .Where(lr => lr.CreatedAt >= cutoffDate) // 新增 .Take(limit) .ToListAsync(); } ``` **说明**: - 添加了创建时间过滤条件 - 影响批量解析接口中 `mode=all` 的查询结果 **1.3 GetOrdersWithLabelsByDateRangeAsync()** ```csharp public async Task> GetOrdersWithLabelsByDateRangeAsync(DateTime startDate, DateTime endDate, int limit = 1000) { var db = _provider.GetClient(); var cutoffDate = new DateTime(2026, 5, 10, 0, 0, 0); // 确保指定的日期范围不低于截断日期 var finalStartDate = startDate < cutoffDate ? cutoffDate : startDate; return await db.Queryable() .Where(lr => !string.IsNullOrEmpty(lr.Label) && lr.CreatedAt >= finalStartDate // 修改 && lr.CreatedAt <= endDate) .Take(limit) .ToListAsync(); } ``` **说明**: - 添加了日期范围检查,确保开始日期不低于截断日期 - 影响批量解析接口中 `mode=range` 的查询结果 **1.4 GetOrdersWithLabelsByCustomerAsync()** ```csharp public async Task> GetOrdersWithLabelsByCustomerAsync(int customerId, int limit = 1000) { var db = _provider.GetClient(); var cutoffDate = new DateTime(2026, 5, 10, 0, 0, 0); return await db.Queryable() .Where(lr => !string.IsNullOrEmpty(lr.Label) && lr.CustomerId == customerId && lr.CreatedAt >= cutoffDate) // 新增 .Take(limit) .ToListAsync(); } ``` **说明**: - 添加了创建时间过滤条件 - 影响批量解析接口中 `mode=customer` 的查询结果 --- ## 工作流程影响 ### 定时任务处理流程 定时任务执行时流程如下: ``` ProcessPendingTasksAsync() ├─ GetInvalidCachesAsync() │ └─ 获取状态=3的无效缓存(结合订单表过滤) │ ├─ GetPendingTasksAsync() │ └─ 获取状态=0和状态=2的待处理缓存 │ └─ GetNewOrdersWithLabelsAsync() ← 新增时间过滤 └─ 获取订单表中有标签但缓存表无记录的订单 └─ 过滤条件: CreatedAt >= 2026-05-10 ``` ### 受影响的查询 | 方法 | 影响 | 说明 | |------|------|------| | `GetNewOrdersWithLabelsAsync()` | ✅ 直接影响 | 定时任务的新订单获取方法 | | `GetAllOrdersWithLabelsAsync()` | ✅ 直接影响 | 批量解析 `mode=all` | | `GetOrdersWithLabelsByDateRangeAsync()` | ✅ 直接影响 | 批量解析 `mode=range` | | `GetOrdersWithLabelsByCustomerAsync()` | ✅ 直接影响 | 批量解析 `mode=customer` | --- ## API 行为变化 ### 批量解析接口 (`/batch-parse`) **修改前**: 可以处理2026-05-10之前的订单 **修改后**: 只能处理2026-05-10及以后的订单 | 模式 | 说明 | 变化 | |------|------|------| | `all` | 处理所有有标签的订单 | ✅ 只处理>=2026-05-10的订单 | | `range` | 按时间范围处理 | ✅ 开始日期自动调整至2026-05-10 | | `customer` | 按客户处理 | ✅ 只处理>=2026-05-10的订单 | | `single` | 单条订单处理 | ❌ 无变化(通过单号直接处理) | ### 示例 **请求 - 按时间范围处理** ```json { "mode": "range", "startDate": "2026-05-01", // 实际从2026-05-10开始 "endDate": "2026-05-15" } ``` **说明**: startDate 会被自动调整为 2026-05-10,因为这是截断日期 --- ## 定时任务行为 ### 定时任务的新特性 1. **自动时间过滤** - 所有查询都将受到创建时间的限制 2. **历史数据隔离** - 2026-05-10之前的订单不会被自动处理 3. **手动处理支持** - 通过 `mode=single` 可以手动处理任何订单 ### 执行间隔 - **间隔**: 5分钟 - **处理范围**: 仅2026-05-10及以后的订单 - **批处理大小**: 100条(可配置) --- ## 配置参数 ### 截断日期定义位置 所有截断日期都定义在数据访问层(Repository)中: ```csharp var cutoffDate = new DateTime(2026, 5, 10, 0, 0, 0); ``` ### 修改截断日期的方法 如需修改截断日期,只需更改上述时间值,例如改为2026-06-01: ```csharp var cutoffDate = new DateTime(2026, 6, 1, 0, 0, 0); ``` 然后重新编译和部署项目。 --- ## 数据库影响 ### 查询变化 **修改前SQL**: ```sql SELECT o.NeutralWaybillNumber FROM label_replace o WHERE o.Label IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM label_pdf_cache c WHERE c.NeutralWaybillNumber = o.NeutralWaybillNumber ) LIMIT 100; ``` **修改后SQL**: ```sql SELECT o.NeutralWaybillNumber FROM label_replace o WHERE o.Label IS NOT NULL AND o.CreatedAt >= '2026-05-10' -- 新增条件 AND NOT EXISTS ( SELECT 1 FROM label_pdf_cache c WHERE c.NeutralWaybillNumber = o.NeutralWaybillNumber ) LIMIT 100; ``` ### 性能考虑 - 添加的 `CreatedAt >= cutoffDate` 条件可以利用现有的时间索引 - 预期查询性能无负面影响 - 可能会减少返回结果数量(因为过滤了旧数据) --- ## 兼容性 ### 向后兼容性 - ✅ 单条处理模式 (`mode=single`) 不受影响 - ❌ 通过API手动处理时会受到时间限制 ### 版本信息 - **修改版本**: v2.1 - **兼容版本**: v2.0(如需处理旧数据,需升级到v2.1后手动处理) --- ## 测试验证 ### 编译验证 ✅ 整个项目已成功编译,无新的编译错误 ### 功能验证清单 - [ ] 定时任务成功运行(每5分钟一次) - [ ] 只处理2026-05-10之后的订单 - [ ] 2026-05-10之前的订单不被处理 - [ ] 批量解析接口在 `mode=all` 时只返回新数据 - [ ] 批量解析接口在 `mode=range` 时正确调整日期范围 - [ ] 批量解析接口在 `mode=customer` 时只返回新客户订单 - [ ] 缓存统计接口统计正确 ### 手动测试命令 ```bash # 测试批量解析 - all模式 curl -X POST http://localhost:5002/api/label/batch-parse \ -H "Content-Type: application/json" \ -d '{"mode":"all","limit":10}' # 测试批量解析 - range模式(时间范围自动调整) curl -X POST http://localhost:5002/api/label/batch-parse \ -H "Content-Type: application/json" \ -d '{"mode":"range","startDate":"2026-05-01","endDate":"2026-05-15","limit":10}' # 测试定时任务状态 curl -X GET http://localhost:5002/api/label/background-service/status ``` --- ## 回滚方案 如需恢复到修改前的行为,只需: 1. 移除所有的 `var cutoffDate = new DateTime(2026, 5, 10, 0, 0, 0);` 定义 2. 移除所有的 `.Where(lr => lr.CreatedAt >= cutoffDate)` 条件 3. 重新编译和部署 --- ## 常见问题 ### Q: 如何处理2026-05-10之前的订单? A: 使用 `mode=single` 通过单号进行手动处理: ```json {"mode":"single","waybillNumber":"1Z999AA10123456784"} ``` ### Q: 定时任务会处理旧订单吗? A: 不会。定时任务 (`GetNewOrdersWithLabelsAsync`) 已被限制为仅处理2026-05-10及以后的订单。 ### Q: 缓存统计会包含旧数据吗? A: 是的。`cache-statistics` 接口统计的是缓存表中的所有数据,不受时间限制。 ### Q: 如何修改截断日期? A: 修改所有Repository中的 `new DateTime(2026, 5, 10, 0, 0, 0)` 为新的日期,然后重新编译部署。 --- ## 相关文件 - **修改的数据库访问类**: `src/DAL/Repositories/LabelReplaceRepository.cs` - **定时任务类**: `src/BLL/Services/LabelPdfCacheService.cs` - **批量解析接口**: `src/CONTROLLER/Controllers/LabelController.cs` --- **修改完成于**: 2026-05-14 **编译状态**: ✅ 成功 **部署状态**: 等待确认