10 KiB
10 KiB
EventLoop: 理想模型推进计划
目标:EventLoop 为唯一状态读/写路径,JobRuntime 退化为复杂动作执行器。 进行中状态 -> 直接转 DB 调度。
当前架构 v1(2026-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 的问题
- 双推进路径:
HandleTaskComplete(JobRuntime)和advanceJobStep(EventLoop)同时存在 - JobRuntime 状态缓存与 DB 不一致风险:内存
Context/PositionType/State可能滞后于 DB jr.Start()是多余的入口:调度应直接从 DB 读状态决定候选,不应依赖 JobRuntime 的enqueueCurrentStepenqueueCurrentStep → 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
改动点:
DBState新增AdvanceStep(ctx, jobID, contextUpdates)方法- 读 job.context + 当前 recipe step
- 计算分支条件 → 下一步索引
- 如果是最后一步 → FinishJob
- 否则 → CompleteStep + 写 context
handleWorkerResultEventLoop 直派路径改为调用db.AdvanceStep- 删除
NotifyStepComplete调用(不再需要 JobRuntime) 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 操作)
改动点:
trySchedule中 MachineWait/Decision/BufferStage 直接调用DBState方法- 删除
SubmitCandidates中的 MachineWait/Decision/BufferStage 直接处理逻辑 SubmitCandidates简化为仅转换 + 入队 Dispatcher- 删除
tryDirectDispatch方法(逻辑移到 trySchedule) - MachineWait 不再写 JobRuntime.State,只写 DB
风险:中——tryDirectDispatch 逻辑需要搬迁到 EventLoop。
Phase 3: 删除旧调度路径
目标:ScheduleAndSubmit 完全被 trySchedule 替代。
现状:
RestoreOrder → ScheduleAndSubmit (旧路径)
trySchedule nil entClient → ScheduleAndSubmit (测试 fallback)
目标:
RestoreOrder → EventLoop.SendScheduleTick → trySchedule
删除 ScheduleAndSubmit 方法
改动点:
RestoreOrder末尾的ScheduleAndSubmit()改为jp.eventLoop.SendScheduleTick()- 删除
ScheduleAndSubmit方法 - 删除
scheduleMu字段(EventLoop 单线程保证序列化) trySchedulenil entClient 路径改为直接 return
风险:低——仅旧的恢复路径受影响,改动量小。
Phase 4: JobRuntime 最小化
目标:JobRuntime 仅保留复杂动作所需的字段和方法。
保留:
buildLoadAction/buildUnloadAction/buildScanAction/buildMarkingAction/buildDecisionAction/buildBufferStageActionexecuteExchange/executeCleaningExchange/executeWasherExchange/executeWasherBatchUnloadhandleMachineDone(由 EventLoop 的 WakeJob 调用)GetState/GetContext(供 Dispatcher 读取)- 所有依赖注入字段(registry, scanner, marker, robotCtrl 等)
删除:
enqueueCurrentStep方法(不再需要)HandleTaskComplete简化(仅复杂动作使用)notifyReady回调 → 删除(调度由 EventLoop 直接触发)syncStatusToDB简化为仅复杂动作使用stepEnqueued/lastEnqueuedStep(不再入队)pendingPause/pendingSuspendReason→ 改为 DB 字段complete()/cleanupOnError()→ 移到 EventLoop
改动点:
- 复杂动作的 ActionFn 闭包完成后,不调
HandleTaskComplete,而是投递 WorkerResult 到 EventLoop exchangePairer逻辑移到 EventLoop 管理- 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.gohandleWorkerResult 直派路径:db.AdvanceStep替代NotifyStepComplete → HandleTaskComplete- Worker 结果不再经过 JobRuntime
Phase 2: trySchedule 直接处理 MachineWait/Decision/BufferStage
trySchedule中新增 3 个方法,直接写 DB:handleMachineWaitCandidate→ DB 写 WaitingUnloadhandleDecisionCandidate→ 读 context + 更新 + AdvanceStephandleBufferStageCandidate→ 读 position + AdvanceStep
SubmitCandidates不再处理这 3 类候选
Phase 3: 删除旧路径
RestoreOrder的ScheduleAndSubmit()改为SendScheduleTick()- 删除
scheduleMu字段(EventLoop 单线程保障序列化) ScheduleAndSubmit保留为 nil entClient fallback
验收标准
go test ./...全量通过- mockrun 1 个 job 完整流程 ≤ 3 分钟完成
- EventLoop.advanceStep 是唯一的步骤推进路径
jp.jobsmap 的写入只发生在 StartOrder/RestoreOrdersyncStatusToDB不包含步骤推进逻辑- 不存在
jr.HandleTaskComplete被简单路径调用的情况