fix(update):修复在线更新检测后缓存问题导致无法正常更新

This commit is contained in:
qian committed 2026-08-28 22:23:00 +08:00
1 parent 958f6c4d75
commit 0964d9014b
3 files changed
+42 -3

No files matched your search

+3 -1
View File
@@ -115,7 +115,9 @@ func (s *sAdmin) UpdateExecute(ctx context.Context, req *v1.UpdateExecuteReq) (*
// Get check result to find download URL
cached := update.GetManager().GetCheckResult()
if cached == nil {
// 缓存里有更新但没匹配到平台安装包时强制重查,而不是直接报「没有可用的更新包」:
// 典型场景是发行版刚发布、CI 尚未上传资产窗口期的检查结果被缓存,资产几分钟后就位
if cached == nil || update.HasUpdateButNoAsset(cached) {
// Force a check first
result, err := update.CheckForUpdate(ctx, true)
if err != nil {
+18 -2
View File
@@ -114,8 +114,11 @@ func CheckForUpdate(ctx context.Context, force bool) (*CheckResult, error) {
// Store ETag for conditional requests
manager.lastETag.Store(etag)
// Cache result
setCheckCache(ctx, result)
// Cache result。「有更新但没匹配到平台安装包」的结果不写 Redis:TTL 24h 太长,
// 会挡住发布窗口期之后的检查拿到完整资产列表(内存结果照常存,供状态展示)
if !HasUpdateButNoAsset(result) {
setCheckCache(ctx, result)
}
manager.checkResult.Store(result)
return result, nil
@@ -185,6 +188,14 @@ func fetchLatestRelease(ctx context.Context, conditional bool) (*GitHubRelease,
return &release, etag, nil
}
// HasUpdateButNoAsset 判断检查结果是否为「有更新但当前平台没匹配到安装包」。
// 典型成因:发行版刚发布、CI 尚未上传资产的窗口期拉到的结果(资产几分钟后才就位)。
// 这类结果不可信:不能写缓存,已入库的脏缓存读到后按无效处理,
// 执行更新时则强制重查,而不是直接报「没有可用的更新包」。
func HasUpdateButNoAsset(r *CheckResult) bool {
return r != nil && r.HasUpdate && r.DownloadURL == ""
}
// getCheckCache reads cached check result from Redis.
// 缓存是纯优化(TTL 24h),Redis 未配置/不可用时应降级为无缓存、走实时检查,
// 绝不能因 g.Redis() 客户端创建失败而 panic(见 goframe-conventions.md 已修复记录)。
@@ -205,6 +216,11 @@ func getCheckCache(ctx context.Context) (out *CheckResult) {
if err := json.Unmarshal(val.Bytes(), &result); err != nil {
return nil
}
// 「有更新但没匹配到平台安装包」的脏缓存(发布窗口期写入,含旧版本遗留数据)按无效处理,
// 让调用方 fallthrough 到实时检查拿完整资产列表
if HasUpdateButNoAsset(&result) {
return nil
}
return &result
}
+21
View File
@@ -46,6 +46,27 @@ func TestCompareVersions(t *testing.T) {
}
}
func TestHasUpdateButNoAsset(t *testing.T) {
cases := []struct {
name string
result *CheckResult
want bool
}{
{"nil 结果", nil, false},
{"有更新且有安装包", &CheckResult{HasUpdate: true, DownloadURL: "https://example.com/team-api-0.2.14-linux-amd64.tar.gz"}, false},
{"无更新且无安装包", &CheckResult{HasUpdate: false, DownloadURL: ""}, false},
{"有更新但缺安装包(发布窗口期脏数据)", &CheckResult{HasUpdate: true, DownloadURL: ""}, true},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
if got := HasUpdateButNoAsset(c.result); got != c.want {
t.Errorf("HasUpdateButNoAsset(%+v) = %v, want %v", c.result, got, c.want)
}
})
}
}
func TestNormalizeSemver(t *testing.T) {
cases := []struct{ in, want string }{
{"0.2.0_39", "0.2.0+39"}, // Makefile git describe 版本:下划线转构建元数据