12 KiB
2026-05-01 系统设计方案对齐重构(第一阶段)设计
背景
本次重构以 系统设计方案.md 为准,对当前系统中与文档冲突的实现进行纠偏。目标不是一次完成全部新架构落地,而是在第一阶段优先完成领域语义统一,为后续 Redis SSOT、事件重放和三层调度器改造打基础。
用户已确认本次采用分阶段迁移,第一阶段范围为:
- 工站域与编排域并行对齐
- 允许修改数据库 schema / ent schema
- 当前代码与文档冲突时,以文档为准
第一阶段目标
第一阶段目标是把系统从“现有实现自定义的一套运行语义”收敛到“系统设计方案.md 定义的语义”,重点完成以下三类一致化:
- 工站域一致化:公开
Station契约以文档定义为准,槽位操作下沉为内部实现细节。 - 编排域一致化:
Job / Task / RecipeStep / Position / Status统一按文档命名和流转。 - 数据模型一致化:数据库 schema 和 ent schema 改为表达文档定义的运行语义,而不是继续围绕旧执行内核组织。
第一阶段结束后,系统可以继续使用现有执行内核的兼容外壳运行,但代码、接口和数据库都必须已经“说文档的语言”。
第一阶段范围
包含
- 统一
JobStatus / TaskStatus / StationStatus / PositionType / StepType等枚举与领域类型 - 重构
internal/station的公开接口 - 重构
internal/processor的公开接口与运行态模型 - 重构
schema/job.go、schema/recipe_step.go - 新增
task、job_step_instanceschema - 让
JobProcessor / JobRuntime / Dispatcher适配新领域模型继续运行 - 做必要的数据迁移与兼容回填
不包含
- Redis 作为运行时单一真相源(SSOT)的完整落地
- Lua 原子版本更新与抢占
- 事件重放能力落地
- 三层调度器完整实现
- PLC 协议与机器人底层通信架构重写
模块边界
station
负责设备抽象、站点状态、命令执行、现场事件接入。
第一阶段中:
Station对上层暴露能力语义,而不是直接暴露槽位增删改查语义- 槽位数组、批处理完成态、换料内部逻辑保留为站点内部实现
processor
负责工单/工件编排、步骤推进、任务生成与状态流转。
第一阶段中:
JobProcessor改造为编排门面(facade)JobRuntime继续存在,但降级为“执行会话对象”,不再作为业务语义真相源RobotTask拆分为领域Task和执行对象两个层次
schema / ent
负责把文档中的运行语义固化为数据库结构,为后续 Redis 和事件模型落地预留字段和引用方式。
核心领域模型
Job
Job 是工件运行态核心实体,第一阶段的主字段以文档为准:
idwork_order_idproduct_type_idrecipe_idcurrent_step_idstatusposition_typeposition_ref_idcontextprioritysuspended_reasonversionlast_event_idcreated_timelast_updated
约束:
current_step_id取代currentStepIndex成为主步骤定位字段position_type + position_ref_id成为主位置表达version + last_event_id在第一阶段先入库,为第二阶段事件一致性铺路
Job 状态机
对外可见状态与数据库状态统一为:
CREATEDIN_HANDLINGPROCESSINGWAITING_UNLOADON_BUFFERWAITING_DECISIONCOMPLETEDSCRAPPEDSUSPENDED
要求:
- 外部接口、数据库枚举、监控输出只允许出现文档状态
- 旧
JobRuntime内部若存在过渡状态,只能作为会话辅助状态,不能暴露为领域状态
Position
位置统一由以下字段表达:
position_typeON_EQUIPMENTON_BUFFERIN_HAND- 迁移期按业务需要兼容
ON_DOCK、ON_SAMPLING
position_ref_id- 指向设备、槽位、接驳台槽位或抽检位等具体位置
约束:
tempSlotNo / onMachineId / onSlot / dockNo / slotNo可作为迁移兼容字段短期保留- 新业务判断只能基于
position_type + position_ref_id
Task
Task 作为明确的领域对象存在,至少包含:
idjob_idtypestatusfrom_posto_posassigned_robotstarted_timecompleted_timeresult- 可选增强:
timeout_at、retry_count
Task 状态机统一为:
CREATEDDISPATCHEDRUNNINGSUCCESSFAILEDTIMEOUT
要求:
- 领域 Task 可持久化、可查询、可审计
RobotTask仅保留为执行对象,不再直接承担完整领域语义
RecipeStep
recipe_step 以文档模型为准,重点字段包括:
step_idrecipe_idstep_namestep_typeresource_typetool_typeallowed_resourcesprocessing_paramsnext_step_defaultnext_step_branchesstep_timeoutdescription
约束:
- 步骤跳转以
step_id为主,而不是stepIndex stepIndex可保留为排序字段,但不再作为主业务引用
JobStepInstance
新增 job_step_instance 用于记录某个 Job 对某个 Step 的一次执行尝试,包括:
job_idstep_idattempt_nostatusequipment_idstart_timeend_timeresult
作用:
- 支撑返工与恢复
- 提供比
job.context更清晰的步骤履历 - 为第二阶段事件重放与审计提供基础
工站接口重构
目标公开接口
第一阶段公开 Station 契约对齐文档语义:
ID() stringType() stringGetStatus() StationStatusCanAccept(jobType string) boolExecute(cmd StationCommand) (assignedSlot string, err error)OnEvent(event StationEvent)
设计原则
ID改为string,统一设备编码表达,避免后续 Redis key 和业务标识反复转换。CanAccept接收jobType,为设备能力约束、机床绑定和工艺过滤预留位置。Execute对外返回 string 型位点引用,便于表达数字槽位、缓冲位、接驳台位等统一位置。- 槽位管理保留,但属于站点内部实现,不再作为上层统一契约。
分层方式
- 公开领域接口层:供 processor / scheduler 使用,只表达站点能力、状态和命令语义。
- 内部状态实现层:保留当前
BaseStation槽位数组、状态迁移、批处理完成与换料逻辑。
状态模型纠偏
当前站点状态从旧语义映射到文档语义:
PROCESSING→BUSYDONE→WAITINGERROR→FAULT
上层只关心是否可继续编排,不直接依赖内部槽位处于 DONE 还是 OCCUPIED。
兼容策略
分两步推进:
- 保留现有
BaseStation与具体站点实现,新增适配层包装成新Station。 - 逐步移除 processor 对
OccupySlot / ReleaseSlot / TransitionSlot / FindSlotByJobID等旧接口的直接依赖,统一通过Execute / OnEvent / GetStatus / CanAccept交互。
编排接口与运行时改造
OrderProcessorInterface
第一阶段保留“工单入口”的结构,但语义改写为文档术语优先:
- 工单控制:
Start / Pause / Resume / Cancel / Restore - 单工件控制:
SuspendJob / ResumeJob / ReworkJob - 监控查询:输出文档定义的状态和值对象,不暴露旧内部状态机语义
JobProcessor
JobProcessor 从“大而全编排器”收缩为第一阶段编排门面:
- 对外仍作为工单编排入口
- 对内协调以下子职责:
JobRepository / TaskRepositoryRecipeResolverRuntimeFactoryTaskDispatcherBufferManagerRecoveryCoordinator(先留接口)
目标不是立刻实现所有拆分,而是先明确责任边界,避免继续把新旧语义堆叠在一个类型中。
JobRuntime
JobRuntime 继续存在,但降级为“执行会话对象”:
- 持有运行时上下文
- 根据
RecipeStep推进步骤 - 响应 Task 完成/失败
- 触发状态落库
约束:
- 不是业务状态真相源
- 领域状态必须与文档状态一致
- 会话辅助状态仅用于执行期控制,不能直接外露
Task 的双层模型
第一阶段明确拆分:
- Task(领域对象)
- 可持久化、可审计
- 表达业务任务状态与位置迁移
- TaskExecution / RobotTask(执行对象)
- 持有
ActionFn - 持有运行时引用
- 由 dispatcher 串行或并发执行
- 持有
迁移结果:
- 数据库与接口看 Task
- 调度执行层看 RobotTask 或等价执行对象
状态推进硬约束
- Job 状态只能走文档允许的迁移
- Task 状态只能走
CREATED -> DISPATCHED -> RUNNING -> SUCCESS/FAILED/TIMEOUT current_step_id是 Job 前进依据job_step_instance记录每次步骤尝试- 暂存台槽位的占用释放只由 Job 终态驱动,不由工件暂时离开槽位驱动
数据库与迁移策略
总体策略
采用 先扩展、再切换、最后清理 的方式:
- 先补齐文档要求的新字段/新表
- 让代码优先读写新语义字段
- 旧字段仅作为短期兼容
- 第一阶段稳定后再评估是否删除旧兼容字段
job 表
保留并强化
workOrderIdproductTypeIdrecipeIdcurrentStepIdstatuspositionTypepositionRefIdcontextprioritysuspendedReasoncreatedTimelastUpdated
新增
versionlastEventId
降级为兼容字段
currentStepIndextempSlotNoonMachineIdonSlotdockNoslotNo
规则:
- 新代码只从新主字段读
- 旧字段只允许迁移期回填或兼容查询
recipe_step 表
第一阶段对齐为文档语义:
step_id作为业务步骤标识next_step_default、next_step_branches统一以步骤 ID 表达跳转- 补齐
step_timeout - 保留
allowed_resources / processing_params / tool_type / resource_type
新增 task 表
用于持久化 Task 领域对象,支持任务状态查询、超时回退和审计。
新增 job_step_instance 表
用于记录 Job 的步骤执行尝试明细,减少上下文字段滥用,支撑返工和恢复。
切换步骤
- 修改 ent schema
- 重新生成 ent 代码
- 改 repository / query 层兼容新旧字段
- 改 processor 使用新字段
- 编写一次性数据迁移逻辑:
currentStepIndex -> currentStepId- 旧位置字段 ->
positionType + positionRefId
- 稳定后再决定是否移除旧字段
实施顺序
建议按以下 6 步推进:
- 统一常量与领域类型
- 先统一
JobStatus / TaskStatus / StationStatus / PositionType / StepType
- 先统一
- 改 schema 与 ent
- 重构
job、recipe_step - 新增
task、job_step_instance
- 重构
- 建立过渡层
- 收口新旧字段映射
- 不让映射逻辑散落在业务代码中
- 重构 station 公共接口
- 先引入新契约与适配层
- 重构 processor 编排入口
JobProcessor改为门面JobRuntime改为执行会话RobotTask拆为领域 Task 与执行对象
- 做数据迁移与回填
- 验证历史数据可被新逻辑正确读取
回归验证
第一阶段至少验证以下路径:
- 工单启动
- 能正确加载 recipe、创建 Job 运行态、进入首个文档定义状态
- 扫码入暂存台
- 成功进入
ON_BUFFER - 失败进入
SUSPENDED
- 成功进入
- 机加工到下料
PROCESSING -> WAITING_UNLOAD -> IN_HANDLING
- 终态释放
COMPLETED / SCRAPPED时释放暂存位
- 任务生命周期
CREATED -> DISPATCHED -> RUNNING -> SUCCESS/FAILED/TIMEOUT
- 恢复 / 返工接口语义
- 即使第二阶段完整恢复体系未落地,接口语义也必须已与文档一致
风险控制
风险 1:新旧状态并存
- 解决:对外只暴露新状态,旧状态只允许存在于适配层内部
风险 2:位置语义混乱
- 解决:业务判断统一只认
positionType + positionRefId
风险 3:步骤跳转仍依赖 index
- 解决:尽快把主流转切到
step_id,stepIndex只保留排序用途
风险 4:上层仍直接操纵工站槽位
- 解决:逐步封口,只允许通过
Execute / OnEvent / GetStatus / CanAccept交互
第一阶段完成标准
第一阶段完成,不以 Redis 已接入为标准,而以下列结果为准:
- 代码、数据库、接口都使用文档定义的术语
- station 与 processor 不再存在一套公开语义、一套内部语义互相冲突的问题
- 旧执行内核仍可运行,但已运行在新领域模型之上
- 第二阶段可以直接接 Redis SSOT、三层调度和事件重放,而不需要再先做一轮术语翻译