Files
bj_power/bj_power_mes/docs/superpowers/specs/2026-05-01-system-design-alignment-phase1-design.md
T

12 KiB
Raw Blame History

2026-05-01 系统设计方案对齐重构(第一阶段)设计

背景

本次重构以 系统设计方案.md 为准,对当前系统中与文档冲突的实现进行纠偏。目标不是一次完成全部新架构落地,而是在第一阶段优先完成领域语义统一,为后续 Redis SSOT、事件重放和三层调度器改造打基础。

用户已确认本次采用分阶段迁移,第一阶段范围为:

  • 工站域与编排域并行对齐
  • 允许修改数据库 schema / ent schema
  • 当前代码与文档冲突时,以文档为准

第一阶段目标

第一阶段目标是把系统从“现有实现自定义的一套运行语义”收敛到“系统设计方案.md 定义的语义”,重点完成以下三类一致化:

  1. 工站域一致化:公开 Station 契约以文档定义为准,槽位操作下沉为内部实现细节。
  2. 编排域一致化Job / Task / RecipeStep / Position / Status 统一按文档命名和流转。
  3. 数据模型一致化:数据库 schema 和 ent schema 改为表达文档定义的运行语义,而不是继续围绕旧执行内核组织。

第一阶段结束后,系统可以继续使用现有执行内核的兼容外壳运行,但代码、接口和数据库都必须已经“说文档的语言”。

第一阶段范围

包含

  • 统一 JobStatus / TaskStatus / StationStatus / PositionType / StepType 等枚举与领域类型
  • 重构 internal/station 的公开接口
  • 重构 internal/processor 的公开接口与运行态模型
  • 重构 schema/job.goschema/recipe_step.go
  • 新增 taskjob_step_instance schema
  • JobProcessor / JobRuntime / Dispatcher 适配新领域模型继续运行
  • 做必要的数据迁移与兼容回填

不包含

  • Redis 作为运行时单一真相源(SSOT)的完整落地
  • Lua 原子版本更新与抢占
  • 事件重放能力落地
  • 三层调度器完整实现
  • PLC 协议与机器人底层通信架构重写

模块边界

station

负责设备抽象、站点状态、命令执行、现场事件接入。

第一阶段中:

  • Station 对上层暴露能力语义,而不是直接暴露槽位增删改查语义
  • 槽位数组、批处理完成态、换料内部逻辑保留为站点内部实现

processor

负责工单/工件编排、步骤推进、任务生成与状态流转。

第一阶段中:

  • JobProcessor 改造为编排门面(facade
  • JobRuntime 继续存在,但降级为“执行会话对象”,不再作为业务语义真相源
  • RobotTask 拆分为领域 Task 和执行对象两个层次

schema / ent

负责把文档中的运行语义固化为数据库结构,为后续 Redis 和事件模型落地预留字段和引用方式。

核心领域模型

Job

Job 是工件运行态核心实体,第一阶段的主字段以文档为准:

  • id
  • work_order_id
  • product_type_id
  • recipe_id
  • current_step_id
  • status
  • position_type
  • position_ref_id
  • context
  • priority
  • suspended_reason
  • version
  • last_event_id
  • created_time
  • last_updated

约束:

  • current_step_id 取代 currentStepIndex 成为主步骤定位字段
  • position_type + position_ref_id 成为主位置表达
  • version + last_event_id 在第一阶段先入库,为第二阶段事件一致性铺路

Job 状态机

对外可见状态与数据库状态统一为:

  • CREATED
  • IN_HANDLING
  • PROCESSING
  • WAITING_UNLOAD
  • ON_BUFFER
  • WAITING_DECISION
  • COMPLETED
  • SCRAPPED
  • SUSPENDED

要求:

  • 外部接口、数据库枚举、监控输出只允许出现文档状态
  • JobRuntime 内部若存在过渡状态,只能作为会话辅助状态,不能暴露为领域状态

Position

位置统一由以下字段表达:

  • position_type
    • ON_EQUIPMENT
    • ON_BUFFER
    • IN_HAND
    • 迁移期按业务需要兼容 ON_DOCKON_SAMPLING
  • position_ref_id
    • 指向设备、槽位、接驳台槽位或抽检位等具体位置

约束:

  • tempSlotNo / onMachineId / onSlot / dockNo / slotNo 可作为迁移兼容字段短期保留
  • 新业务判断只能基于 position_type + position_ref_id

Task

Task 作为明确的领域对象存在,至少包含:

  • id
  • job_id
  • type
  • status
  • from_pos
  • to_pos
  • assigned_robot
  • started_time
  • completed_time
  • result
  • 可选增强:timeout_atretry_count

Task 状态机统一为:

  • CREATED
  • DISPATCHED
  • RUNNING
  • SUCCESS
  • FAILED
  • TIMEOUT

要求:

  • 领域 Task 可持久化、可查询、可审计
  • RobotTask 仅保留为执行对象,不再直接承担完整领域语义

RecipeStep

recipe_step 以文档模型为准,重点字段包括:

  • step_id
  • recipe_id
  • step_name
  • step_type
  • resource_type
  • tool_type
  • allowed_resources
  • processing_params
  • next_step_default
  • next_step_branches
  • step_timeout
  • description

约束:

  • 步骤跳转以 step_id 为主,而不是 stepIndex
  • stepIndex 可保留为排序字段,但不再作为主业务引用

JobStepInstance

新增 job_step_instance 用于记录某个 Job 对某个 Step 的一次执行尝试,包括:

  • job_id
  • step_id
  • attempt_no
  • status
  • equipment_id
  • start_time
  • end_time
  • result

作用:

  • 支撑返工与恢复
  • 提供比 job.context 更清晰的步骤履历
  • 为第二阶段事件重放与审计提供基础

工站接口重构

目标公开接口

第一阶段公开 Station 契约对齐文档语义:

  • ID() string
  • Type() string
  • GetStatus() StationStatus
  • CanAccept(jobType string) bool
  • Execute(cmd StationCommand) (assignedSlot string, err error)
  • OnEvent(event StationEvent)

设计原则

  1. ID 改为 string,统一设备编码表达,避免后续 Redis key 和业务标识反复转换。
  2. CanAccept 接收 jobType,为设备能力约束、机床绑定和工艺过滤预留位置。
  3. Execute 对外返回 string 型位点引用,便于表达数字槽位、缓冲位、接驳台位等统一位置。
  4. 槽位管理保留,但属于站点内部实现,不再作为上层统一契约。

分层方式

  • 公开领域接口层:供 processor / scheduler 使用,只表达站点能力、状态和命令语义。
  • 内部状态实现层:保留当前 BaseStation 槽位数组、状态迁移、批处理完成与换料逻辑。

状态模型纠偏

当前站点状态从旧语义映射到文档语义:

  • PROCESSINGBUSY
  • DONEWAITING
  • ERRORFAULT

上层只关心是否可继续编排,不直接依赖内部槽位处于 DONE 还是 OCCUPIED

兼容策略

分两步推进:

  1. 保留现有 BaseStation 与具体站点实现,新增适配层包装成新 Station
  2. 逐步移除 processor 对 OccupySlot / ReleaseSlot / TransitionSlot / FindSlotByJobID 等旧接口的直接依赖,统一通过 Execute / OnEvent / GetStatus / CanAccept 交互。

编排接口与运行时改造

OrderProcessorInterface

第一阶段保留“工单入口”的结构,但语义改写为文档术语优先:

  • 工单控制:Start / Pause / Resume / Cancel / Restore
  • 单工件控制:SuspendJob / ResumeJob / ReworkJob
  • 监控查询:输出文档定义的状态和值对象,不暴露旧内部状态机语义

JobProcessor

JobProcessor 从“大而全编排器”收缩为第一阶段编排门面:

  • 对外仍作为工单编排入口
  • 对内协调以下子职责:
    • JobRepository / TaskRepository
    • RecipeResolver
    • RuntimeFactory
    • TaskDispatcher
    • BufferManager
    • RecoveryCoordinator(先留接口)

目标不是立刻实现所有拆分,而是先明确责任边界,避免继续把新旧语义堆叠在一个类型中。

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 终态驱动,不由工件暂时离开槽位驱动

数据库与迁移策略

总体策略

采用 先扩展、再切换、最后清理 的方式:

  1. 先补齐文档要求的新字段/新表
  2. 让代码优先读写新语义字段
  3. 旧字段仅作为短期兼容
  4. 第一阶段稳定后再评估是否删除旧兼容字段

job 表

保留并强化

  • workOrderId
  • productTypeId
  • recipeId
  • currentStepId
  • status
  • positionType
  • positionRefId
  • context
  • priority
  • suspendedReason
  • createdTime
  • lastUpdated

新增

  • version
  • lastEventId

降级为兼容字段

  • currentStepIndex
  • tempSlotNo
  • onMachineId
  • onSlot
  • dockNo
  • slotNo

规则:

  • 新代码只从新主字段读
  • 旧字段只允许迁移期回填或兼容查询

recipe_step 表

第一阶段对齐为文档语义:

  • step_id 作为业务步骤标识
  • next_step_defaultnext_step_branches 统一以步骤 ID 表达跳转
  • 补齐 step_timeout
  • 保留 allowed_resources / processing_params / tool_type / resource_type

新增 task 表

用于持久化 Task 领域对象,支持任务状态查询、超时回退和审计。

新增 job_step_instance 表

用于记录 Job 的步骤执行尝试明细,减少上下文字段滥用,支撑返工和恢复。

切换步骤

  1. 修改 ent schema
  2. 重新生成 ent 代码
  3. 改 repository / query 层兼容新旧字段
  4. 改 processor 使用新字段
  5. 编写一次性数据迁移逻辑:
    • currentStepIndex -> currentStepId
    • 旧位置字段 -> positionType + positionRefId
  6. 稳定后再决定是否移除旧字段

实施顺序

建议按以下 6 步推进:

  1. 统一常量与领域类型
    • 先统一 JobStatus / TaskStatus / StationStatus / PositionType / StepType
  2. 改 schema 与 ent
    • 重构 jobrecipe_step
    • 新增 taskjob_step_instance
  3. 建立过渡层
    • 收口新旧字段映射
    • 不让映射逻辑散落在业务代码中
  4. 重构 station 公共接口
    • 先引入新契约与适配层
  5. 重构 processor 编排入口
    • JobProcessor 改为门面
    • JobRuntime 改为执行会话
    • RobotTask 拆为领域 Task 与执行对象
  6. 做数据迁移与回填
    • 验证历史数据可被新逻辑正确读取

回归验证

第一阶段至少验证以下路径:

  1. 工单启动
    • 能正确加载 recipe、创建 Job 运行态、进入首个文档定义状态
  2. 扫码入暂存台
    • 成功进入 ON_BUFFER
    • 失败进入 SUSPENDED
  3. 机加工到下料
    • PROCESSING -> WAITING_UNLOAD -> IN_HANDLING
  4. 终态释放
    • COMPLETED / SCRAPPED 时释放暂存位
  5. 任务生命周期
    • CREATED -> DISPATCHED -> RUNNING -> SUCCESS/FAILED/TIMEOUT
  6. 恢复 / 返工接口语义
    • 即使第二阶段完整恢复体系未落地,接口语义也必须已与文档一致

风险控制

风险 1:新旧状态并存

  • 解决:对外只暴露新状态,旧状态只允许存在于适配层内部

风险 2:位置语义混乱

  • 解决:业务判断统一只认 positionType + positionRefId

风险 3:步骤跳转仍依赖 index

  • 解决:尽快把主流转切到 step_idstepIndex 只保留排序用途

风险 4:上层仍直接操纵工站槽位

  • 解决:逐步封口,只允许通过 Execute / OnEvent / GetStatus / CanAccept 交互

第一阶段完成标准

第一阶段完成,不以 Redis 已接入为标准,而以下列结果为准:

  • 代码、数据库、接口都使用文档定义的术语
  • station 与 processor 不再存在一套公开语义、一套内部语义互相冲突的问题
  • 旧执行内核仍可运行,但已运行在新领域模型之上
  • 第二阶段可以直接接 Redis SSOT、三层调度和事件重放,而不需要再先做一轮术语翻译