每一套 RFID 与 Odoo 集成的第一版都长得一样。读写器被配置成把每一次标签读取都 POST 给一个控制器,控制器直接去写 stock.quant,然后一周之内数据库开始锁表、Odoo worker 被占满,而库存以一种谁也无法复现的方式变错了。
错误是架构性的,不是技术性的。读写器是传感器,不是交易来源。在一个每秒上报成千上万次的传感器,与一个期待「经过思考的业务事件」的 ERP 之间,必须有一个会思考的东西。那个东西就是网关,而在能跑起来的部署里,它才是你维护、版本化、监控的那部分——它是产品,不是胶水。
为什么把读写器直接接进 Odoo 是个反模式
在写任何代码之前,数字已经说明了问题。
- 门口一台固定式读写器,在托盘通过时每秒会吐出几百条 TagRead 事件。
- 同一枚标签在一秒内通常会被读到五到二十次,信号强度各不相同。
- Odoo 的 ORM 会按「产品 / 库位 / 批次」计算并写入一行 quant,每次写入都带行锁与缓存失效。
- 同一行 quant 上的并发写入会退化成锁等待,而多行更新顺序不对就会死锁。
- 读写器一旦断线再恢复,会重放一个突发,而这个突发恰好落在 ERP 最吞不下它的时候。
网关的三个职责:解析、去重、聚合
把这三件事做好的网关可以是两百行代码;做不好的,会被重写两次。
- 解析:把原始 EPC 变成产品、批次与序列号,且不在热路径上查数据库。
- 去重:每枚标签每个时间窗只保留一次观测,而不是二十次,并保留其中信号最强的一次。
- 聚合:把观测变成按库位与产品的带符号增量——这是 Odoo 唯一应该看到的东西。
- 缓冲:增量落在可持久化的队列里,重启不丢,重试安全。
- 写入:批量写 Odoo,并带一个幂等键,使重复写入成为空操作。
从 EPC 到产品:确定性映射
EPC 解析是集成悄悄崩掉的地方,因为它常常是靠字符串截取而不是靠模式完成的。
- 96 位 SGTIN 编码了公司前缀、物品参考号与序列号;切分点取决于前缀长度,而不取决于字符串。
- 先解头部,再解分区,最后解字段;靠猜字段宽度,能一直撑到它撑不住的那天。
- 维护一张「物品参考号 → 产品与批次」的缓存映射,按定时器刷新,而不是每次读取都查。
- 未知 EPC 要进一条显式队列,而不是变成 null;一枚未知标签是贴标或写标缺陷,值得被看见。
- 给映射规则做版本,因为供应商改变标签编码不应该要求一次代码发布。
写入 stock.quant 而不死锁
写入路径是大多数项目丢掉一个周末的地方。规则很简单,主要关乎顺序。
- 每个数据库只跑一个写入进程;这里的并发买不到你需要的吞吐,却买得到死锁。
- 优先用 ORM 里那个带正确锁的原子数量更新方法,绝不要在 Python 里做「读—改—写」。
- 如果必须用 SQL,就按确定性顺序加锁——先产品、再库位、再批次——让两个事务无法交叉。
- 按库位批量,而不是按标签批量:一条货道里的五十个增量属于一个事务,不是五十个。
- 每一次调整都要写上业务原因,因为在审计里,一笔没有解释的数量变化与一个 bug 无法区分。
两个真相冲突时怎么办
读写器与 ERP 一定会不一致,设计问题是:谁被允许赢,以及在什么时候。
- 一次读取是关于「现在」的证据;ERP 记录是关于「过去」的主张。它们不是同一类事实。
- 绝不要让单次读取覆盖数量;只在观测完整、区域关闭时应用增量。
- 用读写器的事件时间,而不是到达网关的时间,否则一批延迟数据会被看成一次新的移动。
- 在事件重复的情况下,最后写入者获胜是不安全的;更稳妥的是每个读写器一个单调序号,并拒绝比已应用更旧的记录。
- 当分歧是结构性的——整个区域差了 10%——应该报异常,而不是悄悄修正。
每天 10 万事件的吞吐工程
十万事件意味着平均每秒一次,而在装卸口可能每秒两百次,所以平均值没有意义。
- 按峰值设计,再验证均值;峰值决定系统会不会坏,均值只决定演示时好不好看。
- 以 0.5 到 2 秒的窗口批量;再短就是白付事务开销,再长就是白付延迟。
- 热路径上不要有 ORM 计算字段、onchange 逻辑与邮件线程;它们都不属于一次库存写入。
- 让写入 worker 跑在作业队列的专用通道上,这样 ERP 变慢不会拖死面向读写器的那一侧。
- 测量去重比;如果低于十倍,说明时间窗太短,Odoo 在做无谓的工作。
可观测性:该记什么、该告什么
一条无法观测的库存管道,会被信任到第一次审计,然后就不再被信任。
- 抽样记录每一条原始事件,全量记录每一条已应用的增量,并附上幂等键。
- 按天线统计读取量,这样一根天线坏掉会表现为曲线上的跌落,而不是安静的一周。
- 对写入延迟超阈值、队列深度持续增长、事件拒绝率上升这三件事告警。
- 每日对账:把网关增量与 Odoo 数量变化对比,凡超过阈值的差异都要解释。
- 保留可重放的事件归档,因为最常见的故障不是崩溃,而是某条错误规则悄悄跑了三天。
上线顺序与回滚
把一条写入路径引入 ERP 的安全方式,是让它先挣得写入的资格。
- 第一阶段:影子模式。只计算增量、只记录、不写入,用两周时间与预期结果对比。
- 第二阶段:用生产流量写沙箱数据库,并在上面跑对账报表。
- 第三阶段:用功能开关只对一个区域开启写入,同时保留旧流程并行。
- 第四阶段:逐区域扩大,盯异常率而不是成功率。
- 回滚不是恢复数据库:停掉写入进程,用修正后的规则重放队列,再幂等重写一遍。






