Files
huachuang/doc/task-service-new-architecture-development-design.md

580 lines
14 KiB
Markdown
Raw Normal View History

2026-07-14 14:09:48 +08:00
# Task 服务新架构详细开发设计方案
## 1. 业务背景与定位
新架构中,系统拆分为通用 `Task` 服务、`LMS` 服务、`WMS` 服务。
其中:
- `LMS`:生产内部搬运业务,例如 AGV 搬运某个架子、托盘、料车到某个生产站点、缓存位、对接位;
- `WMS`仓储出入库业务例如入库、出库、移库、堆垛机搬运、AGV 和立库设备联动;
- `Task`:统一任务服务,负责任务创建记录、任务状态流转、调度下发外部系统、接收外部反馈、任务日志、重试和补偿。
旧架构中 `AbstractAcsTask` 同时承担了任务创建、点位计算、外部下发、完成业务、取消业务等职责。新架构建议将其拆分,避免 Task 服务反向依赖 LMS/WMS 的业务实现。
## 2. 总体设计目标
1. Task 服务成为通用任务中台,只处理任务生命周期和外部系统交互;
2. LMS/WMS 保留各自业务语义和业务数据处理能力;
3. 不再跨服务使用 Java 类名 `handle_class`
4. 使用稳定的 `handler_code` 标识业务处理器;
5. 任务完成、取消时,由 Task 服务通知业务归属服务执行业务回调;
6. 支持 AGV、堆垛机、ACS、WCS 等多种外部系统;
7. 支持同步 RPC 回调,也能平滑演进到 MQ 事件回调;
8. 支持幂等、重试、补偿和人工干预。
## 3. 核心拆分思想
旧版一个 `AbstractAcsTask` 拆成三层能力:
```text
业务任务创建层LMS/WMS
负责业务校验、点位计算、业务参数准备、调用 Task 创建任务
通用任务执行层Task
负责任务状态、任务下发、外部反馈、任务日志、重试补偿
业务结果处理层LMS/WMS
负责完成/取消后的业务确认、库存、单据、点位、分配明细处理
```
对应代码抽象:
```text
LMS/WMSBusinessTaskCreator可选
TaskExternalTaskDispatcher
LMS/WMSTaskBizCallbackHandler
```
## 4. 服务职责边界
### 4.1 LMS 服务职责
LMS 负责生产内部搬运任务的业务语义,例如:
- 判断某个架子是否允许搬运;
- 判断目标站点、缓存位、对接位是否可用;
- 生成生产搬运业务记录;
- 调用 Task 服务创建搬运任务;
- 任务完成后更新生产业务状态;
- 任务取消后回滚生产占用、点位锁定、业务单据状态。
### 4.2 WMS 服务职责
WMS 负责仓储出入库任务的业务语义,例如:
- 入库、出库、移库业务校验;
- 库位分配、库存预占、出入库单据状态维护;
- 调用 Task 服务创建 AGV/堆垛机/输送线任务;
- 任务完成后确认出入库或移库;
- 任务取消后释放库位、回滚库存预占、恢复单据状态。
### 4.3 Task 服务职责
Task 服务只处理通用任务能力:
- 保存任务主表;
- 保存任务明细或任务步骤;
- 管理任务状态机;
- 根据 `external_system` 选择外部系统下发器;
- 下发 AGV/ACS/WCS/堆垛机任务;
- 接收外部系统反馈;
- 根据 `owner_service` 通知 LMS/WMS 做业务回调;
- 记录任务日志;
- 处理重试、超时和补偿。
Task 服务不直接处理 LMS/WMS 的业务表,不直接注入 LMS/WMS 的业务 Service。
## 5. 模块依赖设计
推荐依赖方向:
```text
lms-server -> task-api
wms-server -> task-api
task-server -> task-api
task-server -> lms-api可选仅 RPC 回调需要
task-server -> wms-api可选仅 RPC 回调需要
```
禁止依赖:
```text
task-server -> lms-server
task-server -> wms-server
```
如果采用 MQ 事件方式Task 服务甚至可以不依赖 `lms-api``wms-api`,只发布标准任务事件。
## 6. 新版任务标识设计
旧版:
```text
handle_class = org.nl.b_lms.sch.tasks.TwoInTask
```
新版:
```text
owner_service = LMS
biz_type = PRODUCTION_TRANSFER
handler_code = LMS_RACK_TO_STATION
biz_id = LMS 业务记录 ID
```
或 WMS
```text
owner_service = WMS
biz_type = INBOUND
handler_code = WMS_INBOUND_STACKER
biz_id = WMS 入库单/分配明细 ID
```
字段含义:
| 字段 | 含义 |
| --- | --- |
| `owner_service` | 任务归属业务服务,决定完成/取消回调给谁 |
| `biz_type` | 业务任务类型,用于查询、统计和权限控制 |
| `handler_code` | 业务回调处理器编码,业务服务内部使用 |
| `biz_id` | 业务侧记录 ID用于回查业务数据 |
| `external_system` | 外部执行系统,例如 AGV、ACS、WCS、STACKER |
| `external_task_type` | 外部系统任务类型 |
## 7. 数据模型建议
### 7.1 task_task 主表
| 字段 | 说明 |
| --- | --- |
| `id` | Task 服务任务 ID |
| `task_no` | 任务编号 |
| `owner_service` | LMS/WMS |
| `biz_type` | 业务类型 |
| `biz_id` | 业务侧 ID |
| `handler_code` | 业务回调处理器编码 |
| `external_system` | 外部系统 |
| `external_task_type` | 外部任务类型 |
| `status` | 任务状态 |
| `priority` | 优先级 |
| `start_point_code` | 起点 |
| `end_point_code` | 终点 |
| `vehicle_code` | 载具、架子、托盘、料车等 |
| `callback_status` | 回调状态 |
| `request_payload` | 创建任务扩展参数 |
| `dispatch_payload` | 下发外部系统参数 |
| `result_payload` | 外部反馈参数 |
| `error_msg` | 异常信息 |
### 7.2 task_task_log 日志表
记录每次状态变化、下发、反馈、回调、取消、重试。
关键字段:
| 字段 | 说明 |
| --- | --- |
| `task_id` | 任务 ID |
| `event_type` | CREATE/DISPATCH/FEEDBACK/CALLBACK/CANCEL/RETRY |
| `from_status` | 原状态 |
| `to_status` | 新状态 |
| `request_json` | 请求参数 |
| `response_json` | 响应参数 |
| `success` | 是否成功 |
| `error_msg` | 错误信息 |
### 7.3 task_callback_log 回调日志表
用于保证业务回调幂等和补偿。
| 字段 | 说明 |
| --- | --- |
| `task_id` | 任务 ID |
| `owner_service` | LMS/WMS |
| `handler_code` | 业务处理器编码 |
| `event_type` | FINISH/CANCEL/EXECUTING |
| `status` | PROCESSING/SUCCESS/FAILED |
| `retry_count` | 重试次数 |
| `error_msg` | 失败原因 |
## 8. 状态机设计
推荐 Task 服务状态:
| 状态 | 含义 |
| --- | --- |
| `CREATED` | 已创建 |
| `READY` | 可下发 |
| `ISSUING` | 下发中 |
| `ISSUED` | 已下发 |
| `EXECUTING` | 外部执行中 |
| `FINISHED_PENDING_CALLBACK` | 外部完成,等待业务完成回调 |
| `FINISHED` | 业务完成后最终完成 |
| `CANCEL_PENDING_EXTERNAL` | 等待外部系统取消 |
| `CANCEL_PENDING_CALLBACK` | 外部取消成功,等待业务取消回调 |
| `CANCELLED` | 业务取消后最终取消 |
| `FAILED` | 失败 |
核心原则:
```text
外部系统完成 != 业务完成
外部系统取消 != 业务取消完成
```
因此必须有 `PENDING_CALLBACK` 中间状态。
## 9. 接口设计
### 9.1 Task 创建接口
```text
POST /rpc-api/task/create
```
请求核心字段:
```json
{
"ownerService": "LMS",
"bizType": "PRODUCTION_TRANSFER",
"bizId": "LMS-BIZ-10001",
"handlerCode": "LMS_RACK_TO_STATION",
"externalSystem": "AGV",
"externalTaskType": "MOVE",
"startPointCode": "CACHE_A01",
"endPointCode": "STATION_01",
"vehicleCode": "RACK_001",
"priority": 1,
"requestPayload": {}
}
```
WMS 入库示例:
```json
{
"ownerService": "WMS",
"bizType": "INBOUND",
"bizId": "IN-DIS-10001",
"handlerCode": "WMS_INBOUND_STACKER",
"externalSystem": "STACKER",
"externalTaskType": "INBOUND",
"startPointCode": "IN_PORT_01",
"endPointCode": "A010101",
"vehicleCode": "PALLET_001",
"priority": 5,
"requestPayload": {}
}
```
### 9.2 外部系统反馈接口
```text
POST /api/task/feedback
```
```json
{
"taskId": 10001,
"externalTaskNo": "ACS-TASK-001",
"externalEventId": "EVT-001",
"status": "FINISHED",
"payload": {}
}
```
### 9.3 取消任务接口
```text
POST /rpc-api/task/cancel
```
```json
{
"taskId": 10001,
"reason": "人工取消"
}
```
### 9.4 业务回调接口
第一阶段建议 RPC同步调用业务服务
```text
POST /rpc-api/lms/task-callback/handle
POST /rpc-api/wms/task-callback/handle
```
```json
{
"taskId": 10001,
"taskNo": "T202607130001",
"eventType": "FINISH",
"bizType": "PRODUCTION_TRANSFER",
"bizId": "LMS-BIZ-10001",
"handlerCode": "LMS_RACK_TO_STATION",
"payload": {}
}
```
## 10. Task 服务核心代码抽象
### 10.1 外部系统下发器
```java
public interface ExternalTaskDispatcher {
String getExternalSystem();
DispatchResult dispatch(TaskDO task);
CancelExternalResult cancelExternal(TaskDO task);
}
```
实现示例:
```text
AgvTaskDispatcher
AcsTaskDispatcher
WcsTaskDispatcher
StackerTaskDispatcher
```
Task 服务根据 `external_system` 选择对应 dispatcher。
### 10.2 业务回调通知器
```java
public interface TaskBizCallbackNotifier {
CallbackResult notifyFinish(TaskDO task);
CallbackResult notifyCancel(TaskDO task);
CallbackResult notifyExecuting(TaskDO task);
}
```
第一阶段可实现为 RPC
```text
RpcTaskBizCallbackNotifier
```
第二阶段可实现为 MQ
```text
MqTaskBizCallbackNotifier
```
## 11. LMS/WMS 业务回调 handler 设计
业务服务内部定义:
```java
public interface TaskBizCallbackHandler {
String getHandlerCode();
void onTaskFinished(TaskCallbackRequest request);
void onTaskCancelled(TaskCallbackRequest request);
default void onTaskExecuting(TaskCallbackRequest request) {}
}
```
LMS 示例:
```java
@Component
public class LmsRackToStationCallbackHandler implements TaskBizCallbackHandler {
@Override
public String getHandlerCode() {
return "LMS_RACK_TO_STATION";
}
@Override
public void onTaskFinished(TaskCallbackRequest request) {
// 更新生产搬运记录完成
// 更新架子当前位置
// 释放起点占用
// 占用目标站点或更新目标站点状态
}
@Override
public void onTaskCancelled(TaskCallbackRequest request) {
// 回滚生产搬运记录
// 释放目标站点锁定
// 恢复架子原状态
}
}
```
WMS 示例:
```java
@Component
public class WmsInboundStackerCallbackHandler implements TaskBizCallbackHandler {
@Override
public String getHandlerCode() {
return "WMS_INBOUND_STACKER";
}
@Override
public void onTaskFinished(TaskCallbackRequest request) {
// 入库确认
// 更新库存
// 更新库位状态
// 更新入库单和分配明细
}
@Override
public void onTaskCancelled(TaskCallbackRequest request) {
// 回滚入库分配
// 释放库位预占
// 恢复入库单状态
}
}
```
业务服务内建立分发器:
```java
@Service
public class TaskBizCallbackDispatcher {
private final Map<String, TaskBizCallbackHandler> handlerMap;
public void dispatch(TaskCallbackRequest request) {
TaskBizCallbackHandler handler = handlerMap.get(request.getHandlerCode());
if (handler == null) {
throw new IllegalArgumentException("未找到处理器:" + request.getHandlerCode());
}
if ("FINISH".equals(request.getEventType())) {
handler.onTaskFinished(request);
} else if ("CANCEL".equals(request.getEventType())) {
handler.onTaskCancelled(request);
} else if ("EXECUTING".equals(request.getEventType())) {
handler.onTaskExecuting(request);
}
}
}
```
## 12. 典型流程
### 12.1 LMS 生产搬运任务
```text
LMS 判断架子 RACK_001 要去 STATION_01
-> LMS 锁定目标站点
-> LMS 创建生产搬运业务记录
-> LMS 调用 Task.createTaskhandler_code = LMS_RACK_TO_STATION
-> Task 下发 AGV
-> AGV 反馈执行中Task 更新 EXECUTING可选通知 LMS
-> AGV 反馈完成Task 更新 FINISHED_PENDING_CALLBACK
-> Task 回调 LMS
-> LMS 更新架子位置、站点状态、业务记录完成
-> Task 更新 FINISHED
```
### 12.2 WMS 入库任务
```text
WMS 入库单分配库位 A010101
-> WMS 锁定库位,生成入库分配
-> WMS 调用 Task.createTaskhandler_code = WMS_INBOUND_STACKER
-> Task 下发堆垛机/AGV
-> 外部系统反馈完成
-> Task 更新 FINISHED_PENDING_CALLBACK
-> Task 回调 WMS
-> WMS 确认入库、更新库存、更新库位、更新单据
-> Task 更新 FINISHED
```
### 12.3 取消任务
```text
用户取消任务
-> Task 判断状态
-> 如果已下发,调用外部系统取消
-> 外部取消成功后 Task 更新 CANCEL_PENDING_CALLBACK
-> Task 回调 LMS/WMS
-> LMS/WMS 执行业务回滚
-> Task 更新 CANCELLED
```
## 13. 幂等与事务
### 13.1 Task 幂等
外部反馈按以下维度幂等:
```text
task_id + external_event_id + status
```
同一个完成反馈不能重复触发业务完成。
### 13.2 业务幂等
LMS/WMS 按以下维度幂等:
```text
task_id + event_type
```
如果业务回调已经成功,再次收到直接返回成功。
### 13.3 跨服务一致性
不做分布式事务,采用最终一致性:
1. Task 更新为 `PENDING_CALLBACK`
2. Task 调用 LMS/WMS
3. LMS/WMS 在本地事务内完成业务更新和回调日志;
4. Task 更新最终状态;
5. 失败则进入重试或人工补偿。
## 14. 开发落地步骤
### 第一阶段:基础 RPC 版本
1.`task-api` 定义任务创建、取消、回调 DTO
2.`task-server` 建任务主表、任务日志表、回调日志表;
3. 实现 Task 创建接口;
4. 实现 `ExternalTaskDispatcher` 和 AGV/ACS/堆垛机下发器;
5. 实现外部反馈接口;
6. 实现 RPC 业务回调通知器;
7. 在 LMS/WMS 实现 `TaskBizCallbackHandler` 和分发器;
8. 打通 LMS 生产搬运和 WMS 入库两个典型任务。
### 第二阶段:增强可靠性
1. 增加回调失败重试定时任务;
2. 增加外部下发失败重试;
3. 增加人工补偿页面;
4. 增加状态流转校验;
5. 增加任务日志和链路追踪。
### 第三阶段MQ 演进
1. Task 服务发布任务完成/取消事件;
2. LMS/WMS 消费事件执行业务;
3. 业务服务回调 Task 确认处理结果;
4. RPC 和 MQ 可按任务类型配置切换。
## 15. 最终建议
不要把 LMS/WMS 的业务 `xxxTask` 子类放到 Task 服务,也不要让 Task 服务依赖 LMS/WMS server。
推荐把旧 `AbstractAcsTask` 拆成:
```text
Task 服务ExternalTaskDispatcher负责外部系统下发和取消
LMS/WMSTaskBizCallbackHandler负责业务完成和业务取消
```
`handle_class` 改为:
```text
owner_service + handler_code
```
这样既保留了旧版“不同任务走不同处理器”的扩展性,又满足新架构下服务边界清晰、依赖方向正确、任务服务通用化的目标。