fix(reliability): 采集器并发去重 + 备份恢复即时重载 + context 贯穿请求链

- CollectorService 安装/卸载按采集器互斥去重(重复触发不再并发 docker rm/run 互踩);删除后卸载失败留日志
- ApplyStagedBackup 替换文件后立即 Reload 内存态,消除「重启前旧内存落盘覆盖恢复文件」竞态;暂存文件名升级 lokistack.json(兼容旧名)
- GetUsage/Validate 全链路 context 贯穿:请求取消即中止 SSH/k8s 查询(异步调用点显式 Background)
This commit is contained in:
opsx committed 2026-10-29 13:29:25 +08:00
1 parent 9daaf7f403
commit 572efc89a4
9 files changed
+180 -29

No files matched your search

+16 -1
View File
@@ -281,7 +281,12 @@ func encryptionKeyFingerprint() string {
// ApplyStagedBackup 把暂存文件应用为正式 DB(调用方负责重启进程)。
func ApplyStagedBackup() (string, error) {
staged := filepath.Join(dataDirPath(), ".restore-pending", "opsxloki.json")
restoreDir := filepath.Join(dataDirPath(), ".restore-pending")
staged := filepath.Join(restoreDir, "lokistack.json")
if _, err := os.Stat(staged); err != nil {
// 兼容旧版暂存文件名
staged = filepath.Join(restoreDir, "opsxloki.json")
}
b, err := os.ReadFile(staged)
if err != nil {
return "", fmt.Errorf("没有待应用的恢复文件: %w", err)
@@ -305,6 +310,16 @@ func ApplyStagedBackup() (string, error) {
return "", err
}
_ = os.Remove(staged)
// 关键:立即把内存态切换为恢复后的数据。否则「替换文件 → 重启」之间,
// 任何一次防抖落盘都会用旧内存态把恢复文件覆盖回去,恢复静默失效。
if db := repository.GetDB(); db != nil {
db.Lock()
if err := db.Reload(); err != nil {
db.Unlock()
return dbPath, fmt.Errorf("恢复文件已生效但内存重载失败(%v),请立即重启进程", err)
}
db.Unlock()
}
return dbPath, nil
}