不能用 Redis Pub/Sub 实现可靠的分布式任务暂停与恢复,因其无状态跟踪、无消息确认、不保存历史,控制信号丢失即不可追溯;应改用 Redis Streams 配合消费者组与 XACK 机制保障命令可靠投递与状态一致性。

不能用 Redis Pub/Sub 实现可靠的分布式任务暂停与恢复。它没有状态跟踪、无消息确认、不保存历史,所有控制信号一旦丢失就不可追溯——你收到的“暂停”指令,可能只是某个 Worker 没连上时被丢掉的那一条。
为什么 SUBSCRIBE 无法承载暂停/恢复语义
Pub/Sub 是纯广播通道,不是控制总线。当你执行 PUBLISH control:pause "now":
- 离线 Worker 完全收不到,且无法补收
- 多个 Worker 同时收到,但没人知道谁真停了、谁卡在中间、谁根本没执行
- 没有
ACK,发布端无法判断指令是否落地 - 没有时间戳或版本号,无法区分“刚发的暂停”和“三分钟前重发的老暂停”
-
SUBSCRIBE连接断开后,未处理的消息直接蒸发,Redis 不缓存、不重投
真正可用的暂停/恢复实现方式(用 Redis Streams)
必须换用支持消费者组和消息确认的结构。核心思路是:把“暂停”“恢复”当作带上下文的命令事件,写入可回溯、可重放的流中。
- 用
XADD task_control * cmd "pause" version "20261019-001"写入控制流 - Worker 启动时用
XREADGROUP GROUP ctl_group worker1 COUNT 1 STREAMS task_control >拉取未处理命令 - 执行完暂停逻辑后,必须调用
XACK task_control ctl_group <id></id>,否则该命令会留在XPENDING中待重试 - 恢复操作同理,但需检查当前状态(例如通过
GET task:state判断是否已在 paused 状态),避免重复生效 - 所有 Worker 应监听同一个消费者组,确保命令只被一个节点消费(非广播)
如果硬要用 Pub/Sub 做轻量通知,必须加兜底层
仅限内部系统、容忍短暂不一致的场景,且必须放弃“强暂停”幻想:
- 发布端发
PUBLISH signal:pause "v20261019-001",同时写入SET task:control:version "v20261019-001"作为权威状态快照 - Worker 收到信号后,立即读
GET task:control:version并比对本地缓存,防止旧消息干扰 - 每个 Worker 自行维护
task:worker:<id>:status</id>,定期用EXPIRE标记心跳,主控端可通过KEYS task:worker:*:status(慎用)或 SCAN 扫描活跃节点 - 绝不依赖订阅连接存活——Worker 必须定时轮询
GET task:control:version,哪怕每 30 秒一次,这是唯一能发现“漏掉暂停”的手段
最易被忽略的点:暂停不是开关动作,而是状态迁移。Pub/Sub 给不了状态,你得自己用 Key + TTL + Version + Heartbeat 四件套拼出来;而 Streams 天然带序号和归属,省掉一半业务逻辑。别省这点事,否则凌晨三点你盯着日志查哪个 Worker 卡在“半暂停”状态时,就明白了。


















