You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
wcs_core/任务执行调度-当前实现记录.md

229 lines
7.1 KiB
Markdown

# 任务执行调度 — 当前实现记录
> 记录时间2026-06-13
> 状态:包材入库 (category=1, type=1) 任务驱动并行执行已跑通
---
## 一、整体架构
```
UI (SystemMonitorView)
├─ [▶ 启动] / [■ 停止] 包材入库调度
└─ SystemMonitorViewModel
└─ MaterialInStoreExecutor (Singleton)
Sln.Wcs.Strategy / MaterialInStoreExecutor
├─ 轮询待执行任务 (每 5 秒)
├─ 多任务并行 (Thread最多 10 个)
├─ 单任务内串行 (逐条 detail)
└─ 设备下发 (AGV/提升机/输送线)
Sln.Wcs.Business / TaskCreateService
└─ 拓扑路由 → 自动生成 LiveTaskQueue + List<LiveTaskDetail>
```
## 二、任务创建
### 输入
| 参数 | 说明 | 示例 |
|------|------|------|
| startBuilding | 起始楼栋 | 13 |
| startFloor | 起始楼层 | 1 |
| startLocation | 起始位置号 | 101 |
| endBuilding | 目标楼栋 | 15 |
| endFloor | 目标楼层 | 3 |
| endLocation | 目标位置号 | 102 |
| taskType | 1入库 / 2出库 | 1 |
| taskCategory | 1包材 / 2成品 / 3托盘 | 1 |
| palletBarcode | 托盘条码 | PALLET001 |
| materialCode | 物料编码 | M001 |
### 输出
```
LiveTaskQueue
├─ taskCode: 自动生成 (yyyyMMddHHmmss + 随机数)
├─ taskType, taskCategory
├─ startPoint, endPoint: 自动拼接为 {building}#_L{floor}_{location}
├─ taskStatus: 1 (待执行)
├─ taskSteps: 明细数量
└─ taskDetails: List<LiveTaskDetail>
```
### 拓扑规则
- 所有楼栋 13# / 14# / 15# 均为 1~5F
- 每栋楼有 1 台提升机,可直达任意楼层(全连接)
- 跨栋仅 2F 连通:
- (13,2) ↔ (14,2):廊桥交接,两段 AGV13# AGV → BRIDGE_13_1414# AGV 从 BRIDGE_13_14 接走)
- (14,2) ↔ (15,2)14# AGV 可驶入 15#,不生成过渡段
### 示例13栋1楼101 → 15栋3楼102
```
路由节点: (13,1) → (13,2) → (14,2) → (15,2) → (15,3)
Detail 1: AGV 13#_L1_101 → 13#_L1_HOIST
Detail 2: 提升机 13#_L1_HOIST → 13#_L2_HOIST
Detail 3: AGV 13#_L2_HOIST → BRIDGE_13_14 (13# AGV)
Detail 4: AGV BRIDGE_13_14 → 15#_L2_HOIST (14# AGV 直达)
Detail 5: 提升机 15#_L2_HOIST → 15#_L3_HOIST
Detail 6: AGV 15#_L3_HOIST → 15#_L3_102
```
## 三、任务执行
### 执行器MaterialInStoreExecutor
**位置**`Sln.Wcs.Strategy/MaterialInStoreExecutor.cs`
**查询条件**
```csharp
taskType == 1 && taskCategory == 1 && taskStatus == 1
```
**轮询间隔**5 秒
### 主循环
```
Start()
└─ Task.Run → RunLoopAsync
└─ while (!cancelled):
ExecuteAsync() ← 阻塞等待所有任务线程完成
await Task.Delay(5000)
```
### 并行策略
```
ExecuteAsync:
查询所有待执行任务
→ foreach task → new Thread:
TaskSemaphore.Wait() ← 最多 10 线程
ProcessOneAsync(task).GetAwaiter().GetResult()
TaskSemaphore.Release()
→ Thread.Join() 等待全部完成
```
### 单任务处理
```
ProcessOneAsync(task):
🔒 lock → taskStatus = 2, Update(task)
foreach detail (按 objId 排序):
if detail 已完成 → continue
🔒 lock → detailStatus = 2, Update(detail)
🔓
下发设备 (根据 deviceType):
1 → DispatchAgvAsync (10s 模拟延迟)
2 → DispatchHoistAsync (20s 模拟延迟,按楼栋限 2 并发)
0 → DispatchConveyorAsync
🔒 lock → detailStatus = 3, Update(detail)
🔓
🔒 lock → taskStatus = 3, Update(task)
```
### 并发控制
| 控制点 | 机制 | 值 |
|--------|------|-----|
| 任务级并发 | `SemaphoreSlim` | 最多 10 个 |
| 提升机并发 | `ConcurrentDictionary<int, SemaphoreSlim>` | 每栋楼 2 台 |
| AGV 并发 | 不限 | — |
| DB 写入 | `lock (DbWriteLock)` 串行化 | — |
| 启停状态 | `lock (_lock)` + `volatile bool` | — |
### 线程安全
- **启停**`lock (_lock)` 保护 `_cts` / `_isRunning`
- **DB 写入**`lock (DbWriteLock)` 保护 SqlSugar UpdateContext 为单例,多线程写入冲突)
- **提升机信号量**`ConcurrentDictionary` 线程安全
- **任务信号量**`SemaphoreSlim` 本身线程安全
- **延迟模拟**`await Task.Delay` 在锁外,多任务并行不受影响
## 四、仓储线程安全
**位置**`Sln.Wcs.Repository/Repository.cs`
```csharp
public Repository(ISqlSugarClient db)
{
itenant = db.AsTenant();
Context = (SqlSugarClient)db; // 直接用 SqlSugarScope内部管理连接池
}
```
`SqlSugarScope` 注册为 Singleton通过 `[Tenant]` 特性自动路由数据库。
## 五、设备下发(当前为模拟)
| 设备 | 方法 | 延迟 | 并发限制 |
|------|------|------|---------|
| AGV | `DispatchAgvAsync` | 10 秒 | 无 |
| 提升机 | `DispatchHoistAsync` | 20 秒 | 每栋楼 2 台 |
| 输送线 | `DispatchConveyorAsync` | 无 | 无 |
后续对接AGV → `HikRoBotDispatchHub.ReciveTask`,提升机 → `HoistDispatchHub.TaskDispatch`
## 六、UI 控制
**系统监控页面** — 顶部卡片:
```
┌──────────────────────────────────────────────┐
│ ● 包材入库调度 运行中 [▶ 启动] [■ 停止] │
└──────────────────────────────────────────────┘
```
按钮绑定:
- 启动 → `MaterialInStoreExecutor.Start()`
- 停止 → `MaterialInStoreExecutor.Stop()`
- 状态指示灯:绿色 = 运行中,红色 = 已停止
## 七、DI 注册
**App.axaml.cs**
```csharp
// Assembly 扫描
Assembly.LoadFrom("Sln.Wcs.Strategy.dll")
// Singleton 注册
services.AddSingleton<MaterialInStoreExecutor>();
```
**依赖关系**
```
MaterialInStoreExecutor (Singleton)
├─ SerilogHelper (Singleton)
├─ ILiveTaskQueueService (Transient, 来自 Scrutor 扫描)
└─ ILiveTaskDetailService (Transient, 来自 Scrutor 扫描)
```
## 八、关键文件
| 文件 | 说明 |
|------|------|
| `Sln.Wcs.Business/TaskCreateService.cs` | 拓扑路由 + 任务创建 |
| `Sln.Wcs.Strategy/MaterialInStoreExecutor.cs` | 包材入库执行器 |
| `Sln.Wcs.Repository/Repository.cs` | 仓储基类(线程安全改造) |
| `Sln.Wcs.UI/ViewModels/SystemMonitorViewModel.cs` | 系统监控 VM启停控制 |
| `Sln.Wcs.UI/Views/SystemMonitorView.axaml` | 系统监控页面 |
| `Sln.Wcs.UI/App.axaml.cs` | DI 注册 |
| `接驳位驱动调度方案.md` | 调度方案设计文档 |
## 九、待优化项
1. **真实设备对接**:替换 `DispatchAgvAsync` / `DispatchHoistAsync` 中的模拟延迟为实际 API 调用
2. **扩展其他类型**:成品入库/出库、托盘入库/出库等(参考 MaterialInStoreExecutor 模板)
3. **DB 写入优化**:去掉 `lock (DbWriteLock)`,从根本上解决 SqlSugar 多线程写入问题(可能需要连接串配置 `Max Pool Size` 或改造仓储层)
4. **任务优先级**:当前 FIFO可按优先级排序
5. **异常恢复**:任务中途停止后重新启动的状态恢复
6. **手动触发**UI 上支持手动输入接驳位 + RFID 触发单条明细执行