# 定时任务源代码参考 ## 文件位置总览 ### 后台服务相关 #### 1. LabelPdfCacheBackgroundService.cs **路径**: `src/CONTROLLER/BackgroundServices/LabelPdfCacheBackgroundService.cs` **作用**: 定时任务的主服务类 **关键内容**: - `ExecuteAsync()` - 后台服务的主方法,每5分钟执行一次 - `TaskIntervalMinutes = 5` - 执行间隔设置 - 依赖注入了 `ILabelPdfCacheService` **示例代码位置**: - 第18行: 执行间隔定义 - 第25-40行: 构造函数和依赖注入 - 第42-70行: ExecuteAsync主方法实现 #### 2. BackgroundServiceManager.cs **路径**: `src/CONTROLLER/BackgroundServices/BackgroundServiceManager.cs` **作用**: 管理后台服务的暂停/恢复 **关键内容**: - `PauseService()` - 暂停服务 - `ResumeService()` - 恢复服务 - `IsRunning()` - 检查运行状态 - `GetCancellationToken()` - 获取取消令牌 --- ### 业务逻辑相关 #### 3. LabelPdfCacheService.cs **路径**: `src/BLL/Services/LabelPdfCacheService.cs` **作用**: PDF缓存的业务逻辑处理 **关键方法**: - `ProcessPendingTasksAsync()` (第235-290行) - 处理失效缓存 - 处理待处理任务 - 处理新订单(仅>=2026-05-10) - `ProcessSingleCacheTaskAsync()` (第291-350行) - 处理单个订单 - 获取PDF字节流 - 同步保存缓存 - 异步识别条码 - `RecognizeBarcodeAsync()` (第450-550行) - 条码识别逻辑 - 支持一维码和二维码 - `GetCacheStatisticsAsync()` (第580-620行) - 获取统计信息 #### 4. LabelPdfCacheBackgroundService.cs 中的调用 **关键代码位置**: 第50-65行 ```csharp var successCount = await cacheService.ProcessPendingTasksAsync(); ``` --- ### 数据访问相关 #### 5. LabelPdfCacheRepository.cs **路径**: `src/DAL/Repositories/LabelPdfCacheRepository.cs` **关键方法**: 1. **GetNewOrdersWithLabelsAsync()** (第142-152行) - 获取新订单(无时间限制) - 用于 batch-parse 接口 2. **GetNewOrdersWithLabelsForBackgroundTaskAsync()** (第183-200行) - 获取新订单(仅>=2026-05-10) - **仅用于定时任务** - 关键代码位置: 第186行 ```csharp var cutoffDate = new DateTime(2026, 5, 10, 0, 0, 0); ``` 3. **GetInvalidCachesAsync()** (第53-65行) - 获取失效缓存 4. **GetPendingTasksAsync()** (第67-85行) - 获取待处理任务 --- ### 接口/API相关 #### 6. LabelController.cs **路径**: `src/CONTROLLER/Controllers/LabelController.cs` **定时任务相关接口**: 1. **batch-parse** (第2510-2640行) - POST `/api/label/batch-parse` - 支持4种模式: all, range, customer, single - 不受时间限制 2. **cache-statistics** (第2652-2670行) - GET `/api/label/cache-statistics` - 获取缓存统计信息 3. **background-service/pause** (需要实现) - POST `/api/label/background-service/pause` - 暂停定时任务 4. **background-service/resume** (需要实现) - POST `/api/label/background-service/resume` - 恢复定时任务 5. **background-service/status** (需要实现) - GET `/api/label/background-service/status` - 查看定时任务状态 --- ## 关键代码片段 ### 定时任务执行流程 **文件**: `LabelPdfCacheService.cs` 第235-290行 ```csharp public async Task ProcessPendingTasksAsync(int maxRetryCount = 3, int batchSize = 100) { var successCount = 0; try { // 第一步:处理失效的缓存 var invalidCaches = await _cacheRepository.GetInvalidCachesAsync(batchSize); // 第二步:处理待处理的任务 var remainingBatchSize = batchSize - invalidCaches.Count; var pendingTasks = await _cacheRepository.GetPendingTasksAsync(maxRetryCount, remainingBatchSize); // 第三步:处理订单表中新的有标签订单(仅>=2026-05-10) var newBatchSize = remainingBatchSize - pendingTasks.Count; if (newBatchSize > 0) { // 使用专用方法获取新订单(受时间限制) var newOrders = await _cacheRepository.GetNewOrdersWithLabelsForBackgroundTaskAsync(newBatchSize); foreach (var waybillNumber in newOrders) { if (await ProcessSingleCacheTask(waybillNumber)) { successCount++; } } } } catch (Exception ex) { _logger.LogError(ex, "Error in ProcessPendingTasksAsync"); } return successCount; } ``` ### 定时任务新订单查询(受时间限制) **文件**: `LabelPdfCacheRepository.cs` 第183-200行 ```csharp public async Task> GetNewOrdersWithLabelsForBackgroundTaskAsync(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(); } ``` ### 通用新订单查询(无时间限制) **文件**: `LabelPdfCacheRepository.cs` 第142-152行 ```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(); } ``` --- ## 配置参数修改位置 ### 1. 执行间隔 (5分钟) **文件**: `LabelPdfCacheBackgroundService.cs` 第18行 ```csharp private const int TaskIntervalMinutes = 5; ``` **改为**: 所需的分钟数 ### 2. 批处理大小 (100条) **文件**: `LabelPdfCacheService.cs` ProcessPendingTasksAsync方法参数 ```csharp public async Task ProcessPendingTasksAsync(int maxRetryCount = 3, int batchSize = 100) ``` **改为**: 所需的批处理大小 ### 3. 重试次数 (3次) **文件**: `LabelPdfCacheService.cs` ProcessPendingTasksAsync方法参数 ```csharp public async Task ProcessPendingTasksAsync(int maxRetryCount = 3, int batchSize = 100) ``` **改为**: 所需的重试次数 ### 4. 时间限制日期 (2026-05-10) **文件**: `LabelPdfCacheRepository.cs` GetNewOrdersWithLabelsForBackgroundTaskAsync方法 ```csharp var cutoffDate = new DateTime(2026, 5, 10, 0, 0, 0); ``` **改为**: 所需的日期 --- ## 依赖关系 ``` LabelPdfCacheBackgroundService ↓ └─→ ILabelPdfCacheService ↓ ├─→ ILabelPdfCacheRepository │ ↓ │ └─→ SqlSugar (数据库) │ └─→ ILogger ``` --- ## 调试技巧 ### 打断点位置 1. **定时任务执行**: `LabelPdfCacheBackgroundService.ExecuteAsync()` 2. **处理逻辑**: `LabelPdfCacheService.ProcessPendingTasksAsync()` 3. **单个订单处理**: `LabelPdfCacheService.ProcessSingleCacheTaskAsync()` 4. **查询新订单**: `LabelPdfCacheRepository.GetNewOrdersWithLabelsForBackgroundTaskAsync()` ### 查看日志 日志文件位置: `logs/` 目录 关键日志关键字: - "Label PDF Cache Background Service is starting" - "Starting label PDF cache processing task" - "Completed label PDF cache processing task" - "Error occurred in label PDF cache background service" --- **最后更新**: 2026-05-14