# Changelog — 订阅 IP 自动刷新 Primary 锁与 last_refresh 持久化 **日期**:2026-06-23 ## 摘要 修复单 worker 生产环境下 Redis 主锁竞态导致 `ip_allowlist_refresh_loop` 永不启动、进程内存订阅 IP 与 DB/实时订阅脱节的问题;将「上次刷新」时间写入 `login_subscription_last_refresh` 并广播。 ## 动机 生产排查发现: - `GET /api/settings/ip-allowlist` 返回的 `subscription_ips` 与 DB、实时拉取订阅结果不一致(内存陈旧)。 - `last_refresh` 长期为空;`nexus:primary_worker` 锁未持有,2 小时后台刷新未运行。 - 容器重启时若 Redis 仍残留旧 PID 锁,单 worker 启动一次抢锁失败后不再重试,后台任务永久禁用。 ## 涉及文件 - `server/main.py` — 单 worker 跳过 Redis 选举;多 worker 启动重试抢锁 - `server/background/ip_allowlist_refresh.py` — 持久化 `login_subscription_last_refresh` - `server/config.py` — 新 settings 键映射 - `server/api/settings.py` — 敏感键列表 - `tests/test_ip_allowlist_sync.py` ## 迁移 / 重启 - 无 DB 迁移(新 key 首次刷新时自动写入)。 - 需重启 API 容器使 primary 修复与刷新循环生效。 ## 验证 ```bash pytest tests/test_ip_allowlist_sync.py tests/test_login_access.py -q ``` 生产:重启后约 5s 内应完成首次订阅刷新;设置页「上次刷新」有值且节点 IP 与订阅一致。