Target Version
3.0-dev。复核基于 origin/3.0-dev 提交 a75fc8721b99e5c0b4421d0c58b5618bbe71ff31(PR #57 )。Redis 依赖故障已具备熔断与 fail-closed 基础,但计数器丢失/回退的检测和恢复仍未实现。
Evidence
common/dao/data_redis.hpp:681-714 的 SeqGen 在 Redis INCR 异常时返回 0/空数组;transmite/source/transmite_server.h:278-315 将其转换为 kSystemUnavailable,PR feat(cache): harden Redis resilience and multilevel caching #57 后依赖故障不会继续发布。
但 SeqGen 正常执行 INCR 前不校验 MySQL 高水位或 generation;Redis key 被删除、旧快照恢复或主从切换回退时,INCR 可成功返回低值,绕过上述 fail-closed。
message/source/message_server.h:1239-1266 仍只在 Message 启动时回填,并传入 max_seq + 1。
common/dao/data_redis.hpp:716-738 把 Redis 当前值提升到传入 base;随后下一次 INCR 产生 max_seq + 2,off-by-one 仍存在。
回填锁超时、Redis/Lua 异常仍只记录日志并继续;readiness 不表达序号保护状态。
PR feat(cache): harden Redis resilience and multilevel caching #57 的 Reliability 当前只覆盖 Redis 整体停止/恢复,没有 key 丢失、计数器回退、并发恢复或启动锁竞争。
Problem or Goal
在保留 Redis 在线分配、MySQL 持久高水位的前提下,保证计数器丢失、回退、故障转移或重启后,新 conversation/user seq 永不小于已持久化高水位。允许 gap,禁止回退和复用。
Scope
Non-goals
不要求序号连续无间隙。
不把全局 message_id 改为会话序号。
不更换 Redis Cluster hash-slot 算法。
不绕过 MySQL 唯一约束或以错误重试隐藏冲突。
Acceptance Criteria
Test-first Plan
在现有 Reliability 层增加 RL-SEQ-01:先写入 MySQL 高水位 N,再删除/回退 Redis key 并并发发送,运行:
make -C tests test-reliability TEST_RUN=TestRL_SEQ_CounterLossNeverRegresses
预期 RED 是产生 1、唯一键冲突或启动回填后首值 N+2。最小 GREEN 先修正 next-value,并为运行期未知 generation 增加 fence;随后运行消息并发、幂等、同步和 BVT 回归。
Risk and Security
恢复查询必须只在不确定状态触发并防止惊群。错误 fencing 会降低可用性,错误放行会破坏顺序与唯一性;回滚不得降低任何已提升高水位。日志不得包含消息正文。
Architecture Impact
Yes。明确 Redis 在线序号与 MySQL 持久高水位之间的 generation/recovery/fence 边界。
Core-flow Impact
Yes。改变 Transmite 分配前置条件、Message 启动/readiness 和 Redis 恢复流程。
Required Skill Updates
更新 technology stack,记录序号权威、generation 与恢复语义。
更新 repository map,登记 recovery/readiness/metrics 入口。
更新 core flows,明确允许 gap、禁止回退/复用及 fail-closed。
更新 case catalog,登记 RL-SEQ-01。
Target Version
3.0-dev。复核基于
origin/3.0-dev提交a75fc8721b99e5c0b4421d0c58b5618bbe71ff31(PR #57)。Redis 依赖故障已具备熔断与 fail-closed 基础,但计数器丢失/回退的检测和恢复仍未实现。Evidence
common/dao/data_redis.hpp:681-714的 SeqGen 在 Redis INCR 异常时返回 0/空数组;transmite/source/transmite_server.h:278-315将其转换为kSystemUnavailable,PR feat(cache): harden Redis resilience and multilevel caching #57 后依赖故障不会继续发布。INCR前不校验 MySQL 高水位或 generation;Redis key 被删除、旧快照恢复或主从切换回退时,INCR可成功返回低值,绕过上述 fail-closed。message/source/message_server.h:1239-1266仍只在 Message 启动时回填,并传入max_seq + 1。common/dao/data_redis.hpp:716-738把 Redis 当前值提升到传入 base;随后下一次 INCR 产生max_seq + 2,off-by-one 仍存在。Problem or Goal
在保留 Redis 在线分配、MySQL 持久高水位的前提下,保证计数器丢失、回退、故障转移或重启后,新 conversation/user seq 永不小于已持久化高水位。允许 gap,禁止回退和复用。
Scope
Non-goals
message_id改为会话序号。Acceptance Criteria
Test-first Plan
在现有 Reliability 层增加
RL-SEQ-01:先写入 MySQL 高水位 N,再删除/回退 Redis key 并并发发送,运行:make -C tests test-reliability TEST_RUN=TestRL_SEQ_CounterLossNeverRegresses预期 RED 是产生 1、唯一键冲突或启动回填后首值 N+2。最小 GREEN 先修正 next-value,并为运行期未知 generation 增加 fence;随后运行消息并发、幂等、同步和 BVT 回归。
Risk and Security
恢复查询必须只在不确定状态触发并防止惊群。错误 fencing 会降低可用性,错误放行会破坏顺序与唯一性;回滚不得降低任何已提升高水位。日志不得包含消息正文。
Architecture Impact
Yes。明确 Redis 在线序号与 MySQL 持久高水位之间的 generation/recovery/fence 边界。
Core-flow Impact
Yes。改变 Transmite 分配前置条件、Message 启动/readiness 和 Redis 恢复流程。
Required Skill Updates
RL-SEQ-01。