多平台发布最怕混在一起:一次状态隔离的教训
做 V4 内容管理系统的时候,我踩过一个坑:微信、小红书、微博的发布状态混在同一个字段里,结果一个平台的异常把另外两个平台的正常流程也搅乱了。
事情是怎么发生的
系统最初的设计很直觉——一篇文章有一个发布状态,draft、published、failed。多平台发布的时候,把这个状态按平台拆开存就行了。听起来没问题。
问题出在「按平台拆开」这步做得不彻底。实际实现中,状态字段是数组,每个元素带一个平台标识和对应状态。查询的时候要遍历数组,更新的时候要找到对应平台的那条记录。这本身不算复杂,但当状态变得更多——queued、processing、retrying、rate_limited——事情就失控了。
有一次微博因为限流进入 rate_limited 状态,触发了一个全局重试逻辑,结果把微信端已经成功发布的状态覆盖成了 retrying。排查了两个小时才发现是状态隔离没做干净。
核心卡点:状态不是标签,是生命周期
这次事故暴露的根本问题是:我一开始就把平台状态当标签用,而不是当独立生命周期管理。
标签思维是「给一篇文章打上各平台的状态标记」,生命周棋思维是「每个平台有自己的发布流程,文章只是它们的共享素材」。
差别很大。标签思维下,一篇文章是主体,平台状态是它的属性。生命周期思维下,一次发布任务才是主体,文章是被多个任务引用的素材。
换了这个视角之后,数据结构自然就变了:不再是文章下面挂一个状态数组,而是每次发布操作都是一条独立记录,有自己的 ID、状态机、重试策略和错误日志。文章本身只负责内容,不管分发。
为什么必须隔离
隔离不是洁癖,是实际需求:
第一,错误不传染。 微博限流不应该影响微信发布。状态隔离之后,每个平台的错误只在自己的生命周期里处理。
第二,重试策略不同。 微信的频率限制和小红书的完全不一样,混在一起根本没法做精细化的重试控制。
第三,可观测性。 出了问题要能快速定位是哪个平台、哪一步、什么原因。混在一起的状态让排查变成考古。
落地之后的效果
状态隔离上线后,最明显的改善不是技术上的,而是心理上的——运营同事不再怕发布失败了。之前一个平台报错,他们不知道会不会连锁影响其他平台,现在很清楚:各管各的,互不干扰。
V4 的多平台发布模块后来再也没有出现过跨平台状态污染的问题。不是因为代码写得多好,是因为数据模型从根上就做对了——每个平台的发布流程是独立的实体,不是一篇文章的附属属性。
做系统设计,最怕的不是复杂,是该分开的东西没分开。