# 定时任务源代码参考

## 文件位置总览

### 后台服务相关

#### 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<int> 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<List<string>> GetNewOrdersWithLabelsForBackgroundTaskAsync(int limit)
{
    var db = _provider.GetClient();
    // 定义截断日期：仅处理2026-05-10之后的订单
    var cutoffDate = new DateTime(2026, 5, 10, 0, 0, 0);
    
    return await db.Queryable<LabelReplaceEntity>()
        .Where(o => !string.IsNullOrEmpty(o.Label))
        .Where(o => o.CreatedAt >= cutoffDate)  // ⭐ 时间限制
        .Where(o => !SqlFunc.Subqueryable<LabelPdfCache>()
            .Where(c => c.NeutralWaybillNumber == o.NeutralWaybillNumber)
            .Any())
        .Select(o => o.NeutralWaybillNumber)
        .Take(limit)
        .ToListAsync();
}
```

### 通用新订单查询（无时间限制）

**文件**: `LabelPdfCacheRepository.cs` 第142-152行
```csharp
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();
}
```

---

## 配置参数修改位置

### 1. 执行间隔 (5分钟)

**文件**: `LabelPdfCacheBackgroundService.cs` 第18行
```csharp
private const int TaskIntervalMinutes = 5;
```
**改为**: 所需的分钟数

### 2. 批处理大小 (100条)

**文件**: `LabelPdfCacheService.cs` ProcessPendingTasksAsync方法参数
```csharp
public async Task<int> ProcessPendingTasksAsync(int maxRetryCount = 3, int batchSize = 100)
```
**改为**: 所需的批处理大小

### 3. 重试次数 (3次)

**文件**: `LabelPdfCacheService.cs` ProcessPendingTasksAsync方法参数
```csharp
public async Task<int> 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
