跳转至

M-REDIS-04 真实 Redis Cluster 负向发布门禁 Delta

日期:2026-08-23 状态:已实现并经真实 Docker Cluster 验证

变更摘要

新增一条不依赖常规集成环境的发布负向门禁:启动三个 cluster-enabled Redis 节点,使用 官方镜像内的 redis-cli --cluster create 建立无副本 Cluster,确认其完整覆盖 16384 slots, 再从宿主机 loopback 暴露的真实节点调用生产 qim_common::redis_runtime::assert_redis_runtime_safe。即使进程环境设置 QIM_REDIS_ALLOW_UNSAFE_DEV=1,结果也必须是 ClusterNotStandalone。

影响文件与职责

文件 职责
compose.redis-cluster-negative.yml 只定义三个 Cluster 节点、独立网络、三个项目专属卷,以及 Docker 自动分配的 loopback 端口。
scripts/integration/redis-cluster-negative.sh 验证依赖,生成唯一项目,建集群、验收拓扑、运行 ignored Rust 测试并精确清理本项目。
crates/qim-common/tests/redis_cluster_rejection.rs 经真实 TCP 连接调用生产安全断言,并证明开发放宽开关不覆盖 Cluster 拒绝。

接口与集成点

没有生产 API、Redis store 或常规集成脚本的接口变化。脚本仅向单次 Cargo 进程传递:

QIM_TEST_REDIS_CLUSTER_ADDR=127.0.0.1:<Docker 自动分配端口>
QIM_REDIS_ALLOW_UNSAFE_DEV=1

测试本身要求两个变量存在且值正确;手工运行却漏变量时失败,不会跳过。

隔离与清理契约

项目名必须是唯一的 qim-redis-cluster-negative-*;启动前若同名项目的 container、network 或 volume 已存在则拒绝复用。主节点的宿主端口默认 0 由 Docker 分配,避免与 16379 及并行门禁冲突。清理只执行:

docker compose --project-name "$QIM_REDIS_CLUSTER_NEGATIVE_PROJECT" \
  --file compose.redis-cluster-negative.yml down --volumes --remove-orphans

它不会调用系统范围 prune、不会按宽泛 label 删除,也不会触及常规集成 Compose 项目。

验证计划

Must Have 证据
三个真实 Cluster 节点 脚本等待每个节点 PONG,然后执行 redis-cli --cluster create。
集群已成形 轮询 cluster_state:ok、cluster_slots_assigned:16384 和三个 connected master。
开发开关仍拒绝 Rust ignored 测试读取 QIM_REDIS_ALLOW_UNSAFE_DEV=1,再用 true 调用生产函数,并精确断言 ClusterNotStandalone。
依赖/收敛失败不可假绿 任何缺失或超时都经 fail 非零退出;测试没有 Option/early return skip。
清理只限本项目 同名残留拒绝复用;trap 仅对本 Compose project 执行 down --volumes。

本次应执行:

bash -n scripts/integration/redis-cluster-negative.sh
cargo test --locked -p qim-common --test redis_cluster_rejection --no-run
cargo clippy --locked -p qim-common --test redis_cluster_rejection -- -D warnings
scripts/integration/redis-cluster-negative.sh

验证结果(2026-08-23):四条命令均通过;最后一项创建了三个真实 Redis 7.4.1 master,redis-cli 确认 16384 slots 全覆盖,ignored 测试结果为 1 passed; 0 failed。 Docker 自动分配的测试端口为 127.0.0.1:1026;trap 随后销毁该唯一项目的资源。

风险与边界

本门禁只验证“当前发布运行时拒绝 Cluster”,不测试 Redis Cluster 的键槽行为,也不把 Cluster 作为受支持的 store 后端。Cluster 形成失败时不应尝试单节点替代;这正是该负向 测试需要捕获的环境失效。