|
|
|
|
@ -0,0 +1,228 @@
|
|
|
|
|
# 任务执行调度 — 当前实现记录
|
|
|
|
|
|
|
|
|
|
> 记录时间: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):廊桥交接,两段 AGV(13# AGV → BRIDGE_13_14,14# 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 Update(Context 为单例,多线程写入冲突)
|
|
|
|
|
- **提升机信号量**:`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 触发单条明细执行
|