fix: 隧道断线自愈 + 修复配置负缓存永久固化(根治「隧道一断即整栈不可用 / 必须重启后端」) #21
Loading…
x
Reference in New Issue
Block a user
No description provided.
Delete Branch "codex/tunnel-selfheal-config-cache-0922"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
目的与范围
远端 RST 会把系统库隧道反复踢掉(09-20 实测当天断 5 次,每次存活 15~25 分钟)。
当前实现把「一次网络抖动」放大成「整个开发栈不可用」,根因有两处,本次一并修掉。
1. 隧道断了却拉着应用陪葬 ——
scripts/start-remote.mjs隧道进程
exit时直接stopChildren(),把后端和前端一起杀掉。于是每一次 RST 都升级成一次「网站打不开」,还得靠外部守护清残留、整树重启才能恢复。
改为「退避重连隧道本身,后端/前端进程不受影响」—— 这正是 autossh 的语义
(autossh 只负责重启 ssh,从不牵连被它服务的应用)。建立失败走 1s→30s 指数退避,
建立成功即重置退避。
顺带补齐保活参数:
TCPKeepAlive=yes、ConnectTimeout=10,探活间隔 30s → 15s,以便更快发现已被对端 RST 的死连接。
2. 配置负缓存被永久固化 ——
backend/src/config/cloudDatabase.js系统库读取失败时把「空候选」写进缓存,而入口判断是
if (cachedCloudConfigCandidates)——[]在 JS 里是 truthy,于是这次失败被永久固化:之后永不重试,直接抛「业务数据库尚未配置」500,隧道恢复了也没用,必须重启后端。
改为「带 TTL 的负缓存」(默认 30s,可用
CLOUD_DB_CONFIG_NEGATIVE_TTL_MS调整):入口用
!== null判断,失败态到期自动重新解析,使隧道恢复后无需人工干预。缓存清理收敛到
invalidateCloudConfigCache()单点,避免日后只清数组、忘了清 TTL 时间戳而退化回「永不过期」。同时让「测试连接」入口显式失效,保证用户改完配置点测试能立即看到真实结果。
顺带把请求超时默认值
600000ms → 60000ms:10 分钟 ×maxAttempts=2最坏挂 20 分钟,用户体感就是「卡死」;冷查实测 16~42s,60s 仍有充足余量。
改动文件(4 个,+336 / -27):
scripts/start-remote.mjsbackend/src/config/cloudDatabase.jsbackend/test/cloudDatabaseConfigCache.test.jstest/remote-access.test.mjs同步与兼容性
origin/main最新提交4946018,无冲突。buildSshArgs的其余参数均未变。CLOUD_DB_CONFIG_NEGATIVE_TTL_MS(不设则默认 30000ms)。start-remote.mjs的main(mode)对外签名未变;新增导出computeTunnelRetryDelay供测试。原
dev-supervisor.mjs可退休(该文件在.workbuddy/内,不受本次提交影响)。验证
测试(均含对照组实验,证明用例真能拦住回归)
cloudDatabaseConfigCache.test.js,锁定负缓存三段语义:TTL 内不重复解析 /到期必须重试 / 上游恢复后自动复原且成功态不被 TTL 淘汰。
对照组:把失败态改回「永不过期」(即旧行为)→ 两条用例如实失败,
报错正是线上症状「配置读取应已恢复,不该再报业务数据库尚未配置」。
test/remote-access.test.mjs补隧道断言。对照组:把stopChildren()加回自愈循环 →「防腐化」用例立即抓住。7/7 通过。
node --test test/*.test.js:340 项 / 339 通过,唯一失败为resilientSecretStore的 Windows 权限断言(0o600vs 实际0o666,环境固有,与本次无关)。node scripts/check-syntax.js通过(151 个文件)。本地实测(真实断线演练)
/health隧道 1 秒内自愈,应用毫发无伤。对照旧行为,这里会是「整树退出 + 等守护 2 分钟重启」。
风险与回退
表面看是「进程还活着但不工作」。缓解:失败分支持续打印
SSH 隧道建立失败(…),<n>ms 后重试,日志可判别;退避封顶 30s 不会打爆对端。比原「永久 500 直到重启」是严格改善。
git revert单个提交即可完全回退,无数据迁移、无 schema 变化、无持久化状态。
待确认
可能需要单独放宽该接口的
options.requestTimeout,请评审时确认。