# 任务执行调度 — 当前实现记录 > 记录时间: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 ``` ## 二、任务创建 ### 输入 | 参数 | 说明 | 示例 | |------|------|------| | 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 ``` ### 拓扑规则 - 所有楼栋 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` | 每栋楼 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 (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 触发单条明细执行