凌晨两点,值班电话响了。Riverside 一家电商仓的主管在电话那头喊:"老米,分拣线疯了!同一个箱子被扫了三遍,格口全堆满了,输送机眼看就要堵死!"

我让他先别碰设备,打开电脑,同时拉两份日志。半小时后电话又打回来,声音都变了:"还真是……WES 把同一个波次发了两遍。"

那一晚分拣线停了将近两个小时才恢复。旺季的夜班,两个小时意味着几千个包裹没出去,第二天客服电话会被打爆。执行层的故障就是这样:它不跟你讲道理,直接拿真金白银说话。

这事我见过太多次了。现场的人永远先说"系统抽风了"。我的经验是:执行层所谓的抽风,十有八九是 WES 和 WCS 在互相打架,而打架的根子几乎都在接口上。今天把我用的排查链路摊开讲,从现象摸到根因。

别急着重启,先让两边的日志对上表

指令冲突最常见的死法:任务重复下发。WES 发了释放指令,网络抖了一下,回执没回来,WES 按预设的超时时间又发了一遍。WCS 照单全收——接口压根没做任务号去重。同一个任务进了分拣队列两次,同一件货就被格口要了两三遍。

排查第一步:同时拉 WES 的任务下发日志和 WCS 的指令接收日志,按任务号一条条对。但有个坑,十个仓八个会中:两边服务器时钟没对齐。WES 写 02:14:03 发出,WCS 写 02:13:47 收到,时间对不上就永远理不清因果。动日志之前,先确认两边都对了 NTP,再确认时区——一边 UTC 一边本地时间的,我见过不止一次。

2021 年我在 Ontario 一个十几万平方英尺的仓栽过这个跟头。交叉带分拣机,旺季半夜同一个包裹在系统里出现三次。两份日志摆在一起:WES 明明白白发了两次释放,间隔正好一个超时周期;WCS 的接收日志里,两个任务号一模一样,照样都执行了。根因一句话:超时重发撞上了没有幂等的接口。

还有一种更气人的死法:状态回传丢了。WCS 明明执行完了,回传的"完成"状态在半路丢了,WES 以为任务没执行,又发一遍。这时候 WCS 的日志干干净净——它确实只收到一次有效执行,问题出在回传链路上。排查时别只看下发方向,回传方向要单独拉一条时间线:WCS 说什么时候回的、WES 说什么时候收的,中间的消息队列有没有堆积。2022 年一个仓就是这么被坑的,消息队列半夜堆了十几分钟,WES 把一整波任务全重发了,现场直接乱套。

这里有个 trade-off:超时设太短,网络稍一抖就误重发;设太长,波次切换和急单又等不起。这个数不能拍脑袋,得按现场网络实测的延迟分布来定,重试次数和退避策略要白纸黑字写进接口文档。很多集成商这块是口头约定的,人一走规矩就没了。

输送分拣线执行层实景

急单插队顶掉的任务,最后都去了哪

急单插队是重灾区。WES 收到急单,把原波次一部分任务标成取消,新任务插进去。但 WCS 的指令早就下到 PLC 了——取消追不上已经在执行的分拣动作。同一件货,旧任务要它去 A 格口,新任务要它去 B 格口,设备听谁的?

排查看两条线:WES 的任务状态机(取消到底发没发、什么时候发的),和 WCS 的指令队列(取消到达时那条指令执行到哪一步了)。关键证据是时间戳差——取消发出的时间减去指令实际完成的执行时间,一算就知道追没追上。

还有个更隐蔽的坑:两边任务号对不上。WES 用自己的任务号,WCS 转一道变成设备指令号,中间靠一张映射表。表一丢,两边各说各话。2023 年我在芝加哥附近一个仓见过:映射表放内存里,WCS 服务半夜一重启全没了,值班工程师对着两份日志愣是找不到同一条任务。解法土但有效:映射表落盘,WCS 日志里同时记 WES 的原任务号,透传到底。顺带说一句,映射表最好能按任务号反查——出问题时你拿着 WES 的任务号,能一键定位到 WCS 那边的设备指令,这个反查能力上线前一定要亲手试一次。

再说个判断:急单该不该"硬插队"?我的 verdict 是,出单量不大的仓别玩这个。急单走独立格口、独立波次,别动正在执行的任务。插队省下的几分钟,不够付一次堵线的代价。真要做,取消必须两段式:先发预取消锁住未执行的指令,再发正式取消;已在执行的走"执行完再回收"的补偿流程。指望一条取消指令追上光速,是对物理定律缺乏尊重。

排查这类问题,我有个固定顺序,屡试不爽:先看 WES 的波次/任务状态,确认取消发出的精确时间;再看 WCS 的指令队列,确认那条指令在取消到达时处在"排队""下发中"还是"执行中";接着看 PLC 侧的实际动作反馈。三层时间线摆在一起,责任归属一目了然——是 WES 发晚了,还是 WCS 吞了取消,还是设备本身来不及响应,藏不住的。

别再问为什么了,把幂等做上

前面两类问题根因其实是一个:接口没做幂等。WES 侧:每个任务带全局唯一任务号,重发时任务号不变;WCS 侧:收到先查"这个任务号处理过没有",处理过直接回成功,不再执行。状态回传也一样:带单调递增序列号,WES 收到乱序或重复回传自己能排明白。

验收时我给集成商三句话,写进合同附件:第一,断网几秒重连,同一任务不得执行两次;第二,WCS 重启后历史任务映射不丢;第三,急单取消正在执行的任务,必须有明确的补偿动作,而不是"取消发出去了就算"。这三条过了,执行层九成的灵异事件不会再发生。别信口头承诺,这三条要当着你的面实测——我见过太多"理论上支持幂等"的系统,网线一拔就原形毕露。

还有个场外坑得提:出问题后 WES 厂商和 WCS 集成商一定会互相甩锅,一个说"我发了是你没收好",一个说"你发的不对我没法收"。我的做法是,合同里写明接口责任分界:WES 负责任务号唯一和重发策略,WCS 负责去重和状态回传序列,映射表持久化归 WCS。分界写清楚了,扯皮的时间能省一半。很多项目这页纸是空的,出事了才发现没人兜底。

我的 verdict 放这儿:九成"系统抽风"都是接口没做幂等。剩下一成,一半是时钟没对齐,一半是人半夜手抖点错了按钮——最后这种我也见过,值班工程师凌晨手动重发了一波任务,第二天非说系统自己发的,日志里操作人姓名写得清清楚楚。所以排查时先看日志再下结论,对机器是这样,对人也是这样。

下次系统上线前,亲手把网线拔几秒再插回去——扛得住这几秒的系统,才敢接旺季的单。