Files
bj_power/bj_power_mes/docs/superpowers/plans/2026-05-10-eventloop-v3-plan.md
T

10 KiB
Raw Blame History

EventLoop: 理想模型推进计划

目标:EventLoop 为唯一状态读/写路径,JobRuntime 退化为复杂动作执行器。 进行中状态 -> 直接转 DB 调度。

当前架构 v12026-05-10

简单路径 (Scan/Mark/Load/Unload):
   EventLoop → Worker dispatch → WorkerResult
            → SetJobContext/Position + NotifyStepComplete
            → JobRuntime.HandleTaskComplete → 步骤推进 → enqueueCurrentStep → notifyReady
            → SendScheduleTick → EventLoop → trySchedule

复杂路径 (Exchange/Cleaning/Washer):
   EventLoop → SubmitCandidates → JobRuntime.buildXxxAction → ActionFn 闭包
            → Dispatcher.Enqueue → robotWorker → task.Execute → jr.HandleTaskComplete

DB 角色:
   - job 表:status, position_type, position_ref_id, current_step_index, temp_slot_no
   - equipment_slot 表:status, current_job_id
   - task 表:仅 Dispatcher 路径使用

v1 的问题

  1. 双推进路径HandleTaskCompleteJobRuntime)和 advanceJobStepEventLoop)同时存在
  2. JobRuntime 状态缓存与 DB 不一致风险:内存 Context/PositionType/State 可能滞后于 DB
  3. jr.Start() 是多余的入口:调度应直接从 DB 读状态决定候选,不应依赖 JobRuntime 的 enqueueCurrentStep
  4. enqueueCurrentStep → notifyReady 仍通过 JobRuntime:简单路径的步骤推进仍需要 JobRuntime

理想架构 v3

                 ┌─────────────────────────────────────┐
                 │           EventLoop (唯一路径)         │
                 │                                     │
  MachineDone ──→│ handleMachineDone                   │
                 │  ├─ DB: slot OCCUPIED→DONE           │
                 │  ├─ wake jobs                        │
                 │  └─ trySchedule                      │
                 │                                     │
  Inspection ───→│ handleInspectionResult               │
                 │  ├─ DB: set context                  │
                 │  ├─ advanceStep (DB only)             │
                 │  └─ trySchedule                      │
                 │                                     │
  WorkerResult ─→│ handleWorkerResult                   │
                 │  ├─ DB: set context/position          │
                 │  ├─ advanceStep (DB only)             │
                 │  └─ trySchedule                      │
                 │                                     │
  Command ──────→│ handleXxx                            │
                 │  └─ trySchedule                      │
                 │                                     │
  trySchedule ──→│ 刷新 DB 快照                          │
                 │  ├─ 构建 JobView + SystemState        │
                 │  ├─ 运行三层调度器                      │
                 │  ├─ MachineWait → 标记 DB              │
                 │  ├─ Decision   → 更新 Context + 推进    │
                 │  ├─ BufferStage → 更新位置 + 推进       │
                 │  ├─ Scan/Mark  → go dispatchWorker     │
                 │  ├─ Load/Unload → go dispatchWorker     │
                 │  └─ Exchange等 → SubmitCandidates       │
                 │       └─ Dispatcher (仅复杂动作)         │
                 │                                     │
  Worker 结果 ──→│ handleWorkerResult                    │
                 │  └─ advanceStep (DB only) → trySchedule │
                 └─────────────────────────────────────┘

  JobRuntime (仅用于复杂动作):
     Exchange/Cleaning/Washer 的 ActionFn 闭包
     不再承担: enqueueCurrentStep, notifyReady, syncStatusToDB
     DB 状态完全由 EventLoop 读写

推进计划(4 个 Phase

Phase 1: 简单路径完全脱离 JobRuntime

目标Scan/Mark/Load/Unload 路径不经过 HandleTaskComplete 而是由 EventLoop 的 handleWorkerResult 直接推进 DB 步骤。

现状

WorkerResult → SetJobContext/Position + NotifyStepComplete
            → jr.HandleTaskComplete → buildBranchConditions
            → GetNextStepIndex → jr.CurrentStepIdx = nextIdx
            → syncStatusToDB → enqueueCurrentStep → notifyReady → SendScheduleTick

目标

WorkerResult → EventLoop.advanceStep(jobID, ctxUpdates)
            → DB: 读 Context → 分支条件 → 写 CurrentStepIndex + Context
            → SendScheduleTick → trySchedule

改动点

  1. DBState 新增 AdvanceStep(ctx, jobID, contextUpdates) 方法
    • 读 job.context + 当前 recipe step
    • 计算分支条件 → 下一步索引
    • 如果是最后一步 → FinishJob
    • 否则 → CompleteStep + 写 context
  2. handleWorkerResult EventLoop 直派路径改为调用 db.AdvanceStep
  3. 删除 NotifyStepComplete 调用(不再需要 JobRuntime
  4. SetJobContext / SetJobPosition 改为 DB 直写

风险:低——不影响复杂路径,简单路径已有 Worker 直派基础。

Phase 2: 调度入口去 JobRuntime 化

目标trySchedule 独立于 JobRuntime 运行,不依赖 SubmitCandidates 的 MachineWait/Decision/BufferStage 处理。

现状

trySchedule → 构建 views → 跑调度器 → Workers + SubmitCandidates
SubmitCandidates → jr.State = WAITING_MACHINE (MachineWait)
                → jr.HandleTaskComplete(...) (Decision/BufferStage)

目标

trySchedule → 构建 views → 跑调度器
          → MachineWait: DB 写 job.status = WAITING_UNLOAD
          → Decision: DB 读 context + 写 context + advanceStep
          → BufferStage: DB 写 position + advanceStep
          → Scan/Mark/Load/Unload: Worker dispatch
          → Exchange等: Dispatcher.Enqueue (不经过 SubmitCandidates 的 JobRuntime 操作)

改动点

  1. trySchedule 中 MachineWait/Decision/BufferStage 直接调用 DBState 方法
  2. 删除 SubmitCandidates 中的 MachineWait/Decision/BufferStage 直接处理逻辑
  3. SubmitCandidates 简化为仅转换 + 入队 Dispatcher
  4. 删除 tryDirectDispatch 方法(逻辑移到 trySchedule
  5. MachineWait 不再写 JobRuntime.State,只写 DB

风险:中——tryDirectDispatch 逻辑需要搬迁到 EventLoop。

Phase 3: 删除旧调度路径

目标ScheduleAndSubmit 完全被 trySchedule 替代。

现状

RestoreOrder → ScheduleAndSubmit (旧路径)
trySchedule nil entClient → ScheduleAndSubmit (测试 fallback)

目标

RestoreOrder → EventLoop.SendScheduleTick → trySchedule
删除 ScheduleAndSubmit 方法

改动点

  1. RestoreOrder 末尾的 ScheduleAndSubmit() 改为 jp.eventLoop.SendScheduleTick()
  2. 删除 ScheduleAndSubmit 方法
  3. 删除 scheduleMu 字段(EventLoop 单线程保证序列化)
  4. trySchedule nil entClient 路径改为直接 return

风险:低——仅旧的恢复路径受影响,改动量小。

Phase 4: JobRuntime 最小化

目标JobRuntime 仅保留复杂动作所需的字段和方法。

保留

  • buildLoadAction/buildUnloadAction/buildScanAction/buildMarkingAction/buildDecisionAction/buildBufferStageAction
  • executeExchange/executeCleaningExchange/executeWasherExchange/executeWasherBatchUnload
  • handleMachineDone (由 EventLoop 的 WakeJob 调用)
  • GetState / GetContext (供 Dispatcher 读取)
  • 所有依赖注入字段(registry, scanner, marker, robotCtrl 等)

删除

  • enqueueCurrentStep 方法(不再需要)
  • HandleTaskComplete 简化(仅复杂动作使用)
  • notifyReady 回调 → 删除(调度由 EventLoop 直接触发)
  • syncStatusToDB 简化为仅复杂动作使用
  • stepEnqueued / lastEnqueuedStep(不再入队)
  • pendingPause / pendingSuspendReason → 改为 DB 字段
  • complete() / cleanupOnError() → 移到 EventLoop

改动点

  1. 复杂动作的 ActionFn 闭包完成后,不调 HandleTaskComplete,而是投递 WorkerResult 到 EventLoop
  2. exchangePairer 逻辑移到 EventLoop 管理
  3. JobRuntime 变成纯粹的 "动作描述符"identity + position + context for closure capture

风险:高——深度改动 JobRuntime 状态机,需要大量回归测试。

优先级建议

Phase 优先级 影响 状态
Phase 1 🔴 简单路径彻底 SSOT 完成 (2026-05-10)
Phase 2 🟡 调度逻辑统一 完成 (2026-05-10)
Phase 3 🟢 清理旧代码 完成 (2026-05-10)
Phase 4 部分 高风险的深度重构 仅移除 toolLocker 死代码 (2026-05-10)

已完成改动

Phase 1: DBState.AdvanceStep

  • dbstate.go 新增 AdvanceStep(ctx, jobID, ctxUpdates, posType, posRefID)
    • 从 DB 读 job → 计算下一步 → 如果是最后步则 FinishJob,否则 CompleteStep
    • 同时更新 position、context
  • loop.go handleWorkerResult 直派路径:db.AdvanceStep 替代 NotifyStepComplete → HandleTaskComplete
  • Worker 结果不再经过 JobRuntime

Phase 2: trySchedule 直接处理 MachineWait/Decision/BufferStage

  • trySchedule 中新增 3 个方法,直接写 DB
    • handleMachineWaitCandidate → DB 写 WaitingUnload
    • handleDecisionCandidate → 读 context + 更新 + AdvanceStep
    • handleBufferStageCandidate → 读 position + AdvanceStep
  • SubmitCandidates 不再处理这 3 类候选

Phase 3: 删除旧路径

  • RestoreOrderScheduleAndSubmit() 改为 SendScheduleTick()
  • 删除 scheduleMu 字段(EventLoop 单线程保障序列化)
  • ScheduleAndSubmit 保留为 nil entClient fallback

验收标准

  • go test ./... 全量通过
  • mockrun 1 个 job 完整流程 ≤ 3 分钟完成
  • EventLoop.advanceStep 是唯一的步骤推进路径
  • jp.jobs map 的写入只发生在 StartOrder/RestoreOrder
  • syncStatusToDB 不包含步骤推进逻辑
  • 不存在 jr.HandleTaskComplete 被简单路径调用的情况