From 45267e02f57c9d5981279f583ce998e7399da2a3 Mon Sep 17 00:00:00 2001 From: YuTang Song <2313186065@qq.com> Date: Tue, 19 May 2026 17:34:57 +0800 Subject: [PATCH 1/5] feat: support clusterName into service config Signed-off-by: YuTang Song <2313186065@qq.com> --- .../aslan/core/service/service/environment.go | 102 +++++++++--------- .../aslan/core/service/service/service.go | 3 + 2 files changed, 55 insertions(+), 50 deletions(-) diff --git a/pkg/microservice/aslan/core/service/service/environment.go b/pkg/microservice/aslan/core/service/service/environment.go index 576bb3005a..79e6d94b02 100644 --- a/pkg/microservice/aslan/core/service/service/environment.go +++ b/pkg/microservice/aslan/core/service/service/environment.go @@ -44,6 +44,7 @@ type DeployableEnv struct { Alias string `json:"alias"` Namespace string `json:"namespace"` ClusterID string `json:"cluster_id"` + ClusterName string `json:"cluster_name"` Services []*types.ServiceWithVariable `json:"services"` GlobalVariableKVs []*commontypes.GlobalVariableKV `json:"global_variable_kvs"` } @@ -83,6 +84,33 @@ func GetDeployableEnvs(svcName, projectName string, production bool) (*Deployabl return resp, nil } +// getClusterNameMap Get cluster name map. +func getClusterNameMap() (map[string]string, error) { + clusters, err := commonrepo.NewK8SClusterColl().List(&commonrepo.ClusterListOpts{}) + if err != nil { + return nil, err + } + + clusterNameMap := make(map[string]string, len(clusters)) + for _, cluster := range clusters { + clusterNameMap[cluster.ID.Hex()] = cluster.Name + } + + return clusterNameMap, nil +} + +// newDeployableEnv New deployable environment. +func newDeployableEnv(templateProduct *template.Product, env *commonmodels.Product, clusterNameMap map[string]string) *DeployableEnv { + return &DeployableEnv{ + EnvName: env.EnvName, + Alias: env.Alias, + Namespace: env.Namespace, + ClusterID: env.ClusterID, + ClusterName: clusterNameMap[env.ClusterID], + GlobalVariableKVs: env.GlobalVariables, + Services: getServiceVariables(templateProduct, env), + } +} type GetKubeWorkloadsResp struct { WorkloadsMap map[string][]string `json:"workloads_map"` @@ -356,20 +384,14 @@ func getAllGeneralEnvs(templateProduct *template.Product, production bool) ([]*D return nil, err } - ret := make([]*DeployableEnv, len(envs)) + clusterNameMap, err := getClusterNameMap() + if err != nil { + return nil, err + } - envNames := make([]string, len(envs)) + ret := make([]*DeployableEnv, len(envs)) for i, env := range envs { - - envNames[i] = env.EnvName - ret[i] = &DeployableEnv{ - EnvName: env.EnvName, - Alias: env.Alias, - Namespace: env.Namespace, - ClusterID: env.ClusterID, - GlobalVariableKVs: env.GlobalVariables, - Services: getServiceVariables(templateProduct, env), - } + ret[i] = newDeployableEnv(templateProduct, env, clusterNameMap) } return ret, nil @@ -388,23 +410,20 @@ func getDeployableShareEnvs(svcName string, templateProduct *template.Product, p return nil, err } + clusterNameMap, err := getClusterNameMap() + if err != nil { + return nil, err + } + ret := make([]*DeployableEnv, 0) for _, baseEnv := range baseEnvs { - - ret = append(ret, &DeployableEnv{ - EnvName: baseEnv.EnvName, - Alias: baseEnv.Alias, - Namespace: baseEnv.Namespace, - ClusterID: baseEnv.ClusterID, - GlobalVariableKVs: baseEnv.GlobalVariables, - Services: getServiceVariables(templateProduct, baseEnv), - }) + ret = append(ret, newDeployableEnv(templateProduct, baseEnv, clusterNameMap)) if !hasSvcInEnv(svcName, baseEnv) { continue } - subEnvs, err := getSubEnvs(baseEnv.EnvName, templateProduct) + subEnvs, err := getSubEnvs(baseEnv.EnvName, templateProduct, clusterNameMap) if err != nil { return nil, err } @@ -424,23 +443,20 @@ func getDeployableShareEnvs(svcName string, templateProduct *template.Product, p return nil, err } + clusterNameMap, err := getClusterNameMap() + if err != nil { + return nil, err + } + ret := make([]*DeployableEnv, 0) for _, baseEnv := range baseEnvs { - - ret = append(ret, &DeployableEnv{ - EnvName: baseEnv.EnvName, - Alias: baseEnv.Alias, - Namespace: baseEnv.Namespace, - ClusterID: baseEnv.ClusterID, - GlobalVariableKVs: baseEnv.GlobalVariables, - Services: getServiceVariables(templateProduct, baseEnv), - }) + ret = append(ret, newDeployableEnv(templateProduct, baseEnv, clusterNameMap)) if !hasSvcInEnv(svcName, baseEnv) { continue } - grayEnvs, err := getGrayEnvs(baseEnv.EnvName, baseEnv.ClusterID, templateProduct) + grayEnvs, err := getGrayEnvs(baseEnv.EnvName, baseEnv.ClusterID, templateProduct, clusterNameMap) if err != nil { return nil, err } @@ -452,7 +468,7 @@ func getDeployableShareEnvs(svcName string, templateProduct *template.Product, p } } -func getSubEnvs(baseEnvName string, templateProduct *template.Product) ([]*DeployableEnv, error) { +func getSubEnvs(baseEnvName string, templateProduct *template.Product, clusterNameMap map[string]string) ([]*DeployableEnv, error) { projectName := templateProduct.ProjectName envs, err := commonrepo.NewProductColl().List(&commonrepo.ProductListOptions{ Name: projectName, @@ -467,20 +483,13 @@ func getSubEnvs(baseEnvName string, templateProduct *template.Product) ([]*Deplo ret := make([]*DeployableEnv, len(envs)) for i, env := range envs { - ret[i] = &DeployableEnv{ - EnvName: env.EnvName, - Alias: env.Alias, - Namespace: env.Namespace, - ClusterID: env.ClusterID, - GlobalVariableKVs: env.GlobalVariables, - Services: getServiceVariables(templateProduct, env), - } + ret[i] = newDeployableEnv(templateProduct, env, clusterNameMap) } return ret, nil } -func getGrayEnvs(baseEnvName, clusterID string, templateProduct *template.Product) ([]*DeployableEnv, error) { +func getGrayEnvs(baseEnvName, clusterID string, templateProduct *template.Product, clusterNameMap map[string]string) ([]*DeployableEnv, error) { projectName := templateProduct.ProjectName envs, err := commonutil.FetchGrayEnvs(context.TODO(), projectName, clusterID, baseEnvName) if err != nil { @@ -489,14 +498,7 @@ func getGrayEnvs(baseEnvName, clusterID string, templateProduct *template.Produc ret := make([]*DeployableEnv, len(envs)) for i, env := range envs { - ret[i] = &DeployableEnv{ - EnvName: env.EnvName, - Alias: env.Alias, - Namespace: env.Namespace, - ClusterID: env.ClusterID, - GlobalVariableKVs: env.GlobalVariables, - Services: getServiceVariables(templateProduct, env), - } + ret[i] = newDeployableEnv(templateProduct, env, clusterNameMap) } return ret, nil diff --git a/pkg/microservice/aslan/core/service/service/service.go b/pkg/microservice/aslan/core/service/service/service.go index a0dd57faf3..99894dafe2 100644 --- a/pkg/microservice/aslan/core/service/service/service.go +++ b/pkg/microservice/aslan/core/service/service/service.go @@ -181,6 +181,9 @@ func GetServiceOption(args *commonmodels.Service, log *zap.SugaredLogger) (*Serv { Key: "$EnvName$", Value: ""}, + { + Key: "$ClusterName$", + Value: ""}, } serviceOption.VariableYaml = args.VariableYaml From 4f8919fb2dcb7d2035dd9cf92901e710f6a21c89 Mon Sep 17 00:00:00 2001 From: YuTang Song <2313186065@qq.com> Date: Tue, 19 May 2026 18:07:44 +0800 Subject: [PATCH 2/5] fix: recover cluster name render in the frontend Signed-off-by: YuTang Song <2313186065@qq.com> --- .../aslan/core/common/service/kube/parse.go | 28 ++++++++++++++++++- .../aslan/core/common/service/kube/render.go | 12 ++++---- .../aslan/core/common/service/service.go | 2 +- .../core/environment/service/configmap.go | 2 +- .../aslan/core/environment/service/kube.go | 2 +- .../aslan/core/environment/service/service.go | 2 +- 6 files changed, 37 insertions(+), 11 deletions(-) diff --git a/pkg/microservice/aslan/core/common/service/kube/parse.go b/pkg/microservice/aslan/core/common/service/kube/parse.go index 9c71df0edb..1e9c740ca4 100644 --- a/pkg/microservice/aslan/core/common/service/kube/parse.go +++ b/pkg/microservice/aslan/core/common/service/kube/parse.go @@ -19,6 +19,9 @@ package kube import ( "regexp" "strings" + "sync" + + commonrepo "github.com/koderover/zadig/v2/pkg/microservice/aslan/core/common/repository/mongodb" ) const ( @@ -30,6 +33,7 @@ const ( envRegexString = `\$EnvName\$` productRegexString = `\$Product\$` serviceRegexString = `\$Service\$` + clusterRegexString = `\$ClusterName\$` ) var ( @@ -41,13 +45,35 @@ var ( productRegex = regexp.MustCompile(productRegexString) envNameRegex = regexp.MustCompile(envRegexString) serviceRegex = regexp.MustCompile(serviceRegexString) + clusterRegex = regexp.MustCompile(clusterRegexString) + + clusterNameCache sync.Map ) +func getClusterName(clusterID string) string { + if clusterID == "" { + return "" + } + + if clusterName, ok := clusterNameCache.Load(clusterID); ok { + return clusterName.(string) + } + + cluster, err := commonrepo.NewK8SClusterColl().FindByID(clusterID) + if err != nil { + return "" + } + + clusterNameCache.Store(clusterID, cluster.Name) + return cluster.Name +} + // ParseSysKeys 渲染系统变量键值 -func ParseSysKeys(namespace, envName, productName, serviceName, ori string) string { +func ParseSysKeys(namespace, envName, productName, serviceName, clusterID, ori string) string { ori = envNameRegex.ReplaceAllLiteralString(ori, strings.ToLower(envName)) ori = namespaceRegex.ReplaceAllLiteralString(ori, strings.ToLower(namespace)) ori = productRegex.ReplaceAllLiteralString(ori, strings.ToLower(productName)) ori = serviceRegex.ReplaceAllLiteralString(ori, strings.ToLower(serviceName)) + ori = clusterRegex.ReplaceAllLiteralString(ori, strings.ToLower(getClusterName(clusterID))) return ori } diff --git a/pkg/microservice/aslan/core/common/service/kube/render.go b/pkg/microservice/aslan/core/common/service/kube/render.go index 3e9f22f94f..97f54a9b42 100644 --- a/pkg/microservice/aslan/core/common/service/kube/render.go +++ b/pkg/microservice/aslan/core/common/service/kube/render.go @@ -412,7 +412,7 @@ func FetchCurrentAppliedYaml(option *GeneSvcYamlOption) (string, int, error) { if err != nil { return "", 0, err } - fullRenderedYaml = ParseSysKeys(productInfo.Namespace, productInfo.EnvName, option.ProductName, option.ServiceName, fullRenderedYaml) + fullRenderedYaml = ParseSysKeys(productInfo.Namespace, productInfo.EnvName, option.ProductName, option.ServiceName, productInfo.ClusterID, fullRenderedYaml) mergedContainers := mergeContainers(prodSvcTemplate.Containers, curProductSvc.Containers) fullRenderedYaml, _, err = ReplaceWorkloadImages(fullRenderedYaml, mergedContainers) if err != nil { @@ -430,7 +430,7 @@ func FetchImportedAllManifests(envInfo *models.Product, serviceTmp *models.Servi if err != nil { return "", nil, err } - fullRenderedYaml = ParseSysKeys(envInfo.Namespace, envInfo.EnvName, envInfo.ProductName, serviceTmp.ServiceName, fullRenderedYaml) + fullRenderedYaml = ParseSysKeys(envInfo.Namespace, envInfo.EnvName, envInfo.ProductName, serviceTmp.ServiceName, envInfo.ClusterID, fullRenderedYaml) manifests := util.SplitManifestsOrdered(fullRenderedYaml) @@ -686,7 +686,7 @@ func FetchImportedManifests(option *GeneSvcYamlOption, productInfo *models.Produ if err != nil { return "", nil, err } - fullRenderedYaml = ParseSysKeys(productInfo.Namespace, productInfo.EnvName, option.ProductName, option.ServiceName, fullRenderedYaml) + fullRenderedYaml = ParseSysKeys(productInfo.Namespace, productInfo.EnvName, option.ProductName, option.ServiceName, productInfo.ClusterID, fullRenderedYaml) manifests := releaseutil.SplitManifests(fullRenderedYaml) @@ -831,7 +831,7 @@ func GenerateRenderedYaml(option *GeneSvcYamlOption) (string, int, []*WorkloadRe if renderErr != nil { return "", 0, nil, renderErr } - currentRenderedYaml = ParseSysKeys(productInfo.Namespace, productInfo.EnvName, option.ProductName, option.ServiceName, currentRenderedYaml) + currentRenderedYaml = ParseSysKeys(productInfo.Namespace, productInfo.EnvName, option.ProductName, option.ServiceName, productInfo.ClusterID, currentRenderedYaml) currentBaseReplicaMap, err = ExtractWorkloadReplicas(currentRenderedYaml) if err != nil { return "", 0, nil, err @@ -860,7 +860,7 @@ func GenerateRenderedYaml(option *GeneSvcYamlOption) (string, int, []*WorkloadRe if err != nil { return "", 0, nil, err } - fullRenderedYaml = ParseSysKeys(productInfo.Namespace, productInfo.EnvName, option.ProductName, option.ServiceName, fullRenderedYaml) + fullRenderedYaml = ParseSysKeys(productInfo.Namespace, productInfo.EnvName, option.ProductName, option.ServiceName, productInfo.ClusterID, fullRenderedYaml) // service may not be deployed in environment, we need to extract containers again, since image related variables may be changed latestSvcTemplate.KubeYamls = util.SplitYaml(fullRenderedYaml) @@ -977,7 +977,7 @@ func RenderEnvServiceWithTempl(prod *commonmodels.Product, serviceRender *templa log.Errorf("failed to render service yaml, err: %s", err) return "", err } - parsedYaml = ParseSysKeys(prod.Namespace, prod.EnvName, prod.ProductName, service.ServiceName, parsedYaml) + parsedYaml = ParseSysKeys(prod.Namespace, prod.EnvName, prod.ProductName, service.ServiceName, prod.ClusterID, parsedYaml) parsedYaml, _, err = ReplaceWorkloadImages(parsedYaml, service.Containers) if err != nil { return "", err diff --git a/pkg/microservice/aslan/core/common/service/service.go b/pkg/microservice/aslan/core/common/service/service.go index 207da6640e..ebba090ab6 100644 --- a/pkg/microservice/aslan/core/common/service/service.go +++ b/pkg/microservice/aslan/core/common/service/service.go @@ -1422,7 +1422,7 @@ func GetServiceImpl(serviceName string, serviceTmpl *commonmodels.Service, workL return nil, err } // 渲染系统变量键值 - parsedYaml = kube.ParseSysKeys(namespace, envName, productName, service.ServiceName, parsedYaml) + parsedYaml = kube.ParseSysKeys(namespace, envName, productName, service.ServiceName, env.ClusterID, parsedYaml) manifests := releaseutil.SplitManifests(parsedYaml) for _, item := range manifests { diff --git a/pkg/microservice/aslan/core/environment/service/configmap.go b/pkg/microservice/aslan/core/environment/service/configmap.go index 2db490da57..f0eae28c0e 100644 --- a/pkg/microservice/aslan/core/environment/service/configmap.go +++ b/pkg/microservice/aslan/core/environment/service/configmap.go @@ -211,7 +211,7 @@ func UpdateConfigMap(args *models.CreateUpdateCommonEnvCfgArgs, userName string, //for _, kv := range renderSet.KVs { // value = strings.Replace(value, kv.Alias, kv.Value, -1) //} - value = kube.ParseSysKeys(product.Namespace, product.EnvName, product.ProductName, args.ServiceName, value) + value = kube.ParseSysKeys(product.Namespace, product.EnvName, product.ProductName, args.ServiceName, product.ClusterID, value) cm.Data[key] = value } diff --git a/pkg/microservice/aslan/core/environment/service/kube.go b/pkg/microservice/aslan/core/environment/service/kube.go index 78d7ffcbaa..bc4369a750 100644 --- a/pkg/microservice/aslan/core/environment/service/kube.go +++ b/pkg/microservice/aslan/core/environment/service/kube.go @@ -983,7 +983,7 @@ func GetResourceDeployStatus(productName string, request *K8sDeployStatusCheckRe if err != nil { return nil, e.ErrGetResourceDeployInfo.AddErr(fmt.Errorf("failed to render service yaml, serviceName:%s, err: %w", svc.ServiceName, err)) } - rederedYaml = kube.ParseSysKeys(request.Namespace, request.EnvName, productName, svc.ServiceName, rederedYaml) + rederedYaml = kube.ParseSysKeys(request.Namespace, request.EnvName, productName, svc.ServiceName, request.ClusterID, rederedYaml) manifests := releaseutil.SplitManifests(rederedYaml) resources := make([]*ResourceDeployStatus, 0) diff --git a/pkg/microservice/aslan/core/environment/service/service.go b/pkg/microservice/aslan/core/environment/service/service.go index 8e40402b14..c18923e0ab 100644 --- a/pkg/microservice/aslan/core/environment/service/service.go +++ b/pkg/microservice/aslan/core/environment/service/service.go @@ -186,7 +186,7 @@ func GetServiceWorkloads(svcTmpl *commonmodels.Service, env *commonmodels.Produc log.Errorf("failed to render service yaml, err: %s", err) return nil, err } - parsedYaml = kube.ParseSysKeys(namespace, envName, productName, svcTmpl.ServiceName, parsedYaml) + parsedYaml = kube.ParseSysKeys(namespace, envName, productName, svcTmpl.ServiceName, env.ClusterID, parsedYaml) manifests := releaseutil.SplitManifests(parsedYaml) for _, item := range manifests { From 3239b19e098000a25040131dfb2f581901e29ad8 Mon Sep 17 00:00:00 2001 From: YuTang Song <2313186065@qq.com> Date: Fri, 22 May 2026 14:02:41 +0800 Subject: [PATCH 3/5] fix: delete clustercache Signed-off-by: YuTang Song <2313186065@qq.com> --- .../aslan/core/common/service/kube/parse.go | 25 +------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/pkg/microservice/aslan/core/common/service/kube/parse.go b/pkg/microservice/aslan/core/common/service/kube/parse.go index 1e9c740ca4..f3091d6788 100644 --- a/pkg/microservice/aslan/core/common/service/kube/parse.go +++ b/pkg/microservice/aslan/core/common/service/kube/parse.go @@ -19,9 +19,6 @@ package kube import ( "regexp" "strings" - "sync" - - commonrepo "github.com/koderover/zadig/v2/pkg/microservice/aslan/core/common/repository/mongodb" ) const ( @@ -46,34 +43,14 @@ var ( envNameRegex = regexp.MustCompile(envRegexString) serviceRegex = regexp.MustCompile(serviceRegexString) clusterRegex = regexp.MustCompile(clusterRegexString) - - clusterNameCache sync.Map ) -func getClusterName(clusterID string) string { - if clusterID == "" { - return "" - } - - if clusterName, ok := clusterNameCache.Load(clusterID); ok { - return clusterName.(string) - } - - cluster, err := commonrepo.NewK8SClusterColl().FindByID(clusterID) - if err != nil { - return "" - } - - clusterNameCache.Store(clusterID, cluster.Name) - return cluster.Name -} - // ParseSysKeys 渲染系统变量键值 func ParseSysKeys(namespace, envName, productName, serviceName, clusterID, ori string) string { ori = envNameRegex.ReplaceAllLiteralString(ori, strings.ToLower(envName)) ori = namespaceRegex.ReplaceAllLiteralString(ori, strings.ToLower(namespace)) ori = productRegex.ReplaceAllLiteralString(ori, strings.ToLower(productName)) ori = serviceRegex.ReplaceAllLiteralString(ori, strings.ToLower(serviceName)) - ori = clusterRegex.ReplaceAllLiteralString(ori, strings.ToLower(getClusterName(clusterID))) + ori = clusterRegex.ReplaceAllLiteralString(ori, strings.ToLower(clusterID)) return ori } From 5f1a22334ad6aa56f3f53b9bcf2f4f1d30f01db1 Mon Sep 17 00:00:00 2001 From: YuTang Song <2313186065@qq.com> Date: Fri, 22 May 2026 16:05:35 +0800 Subject: [PATCH 4/5] pref(kube): add product cache Signed-off-by: YuTang Song <2313186065@qq.com> --- .../core/common/service/kube/product_cache.go | 96 +++++++++++++++++++ .../aslan/core/common/service/kube/render.go | 4 +- .../core/environment/service/configmap.go | 6 +- 3 files changed, 101 insertions(+), 5 deletions(-) create mode 100644 pkg/microservice/aslan/core/common/service/kube/product_cache.go diff --git a/pkg/microservice/aslan/core/common/service/kube/product_cache.go b/pkg/microservice/aslan/core/common/service/kube/product_cache.go new file mode 100644 index 0000000000..5de53a429a --- /dev/null +++ b/pkg/microservice/aslan/core/common/service/kube/product_cache.go @@ -0,0 +1,96 @@ +package kube + +import ( + "fmt" + "sync" + "time" + + commonmodels "github.com/koderover/zadig/v2/pkg/microservice/aslan/core/common/repository/models" + commonrepo "github.com/koderover/zadig/v2/pkg/microservice/aslan/core/common/repository/mongodb" + "github.com/koderover/zadig/v2/pkg/util" +) + +type productCacheItem struct { + product *commonmodels.Product + expireAt time.Time +} + +var ( + productCache sync.Map + productCacheTTL = 30 * time.Second + productNow = time.Now + loadProductFunc = func(opt *commonrepo.ProductFindOptions) (*commonmodels.Product, error) { + return commonrepo.NewProductColl().Find(opt) + } +) + +// GetProductWithCache 优先从内存缓存读取 product 元数据。 +// 如果缓存未命中或已过期,则重新查库并刷新缓存。 +// 返回值始终是深拷贝,避免调用方修改缓存中的原始对象。 +func GetProductWithCache(opt *commonrepo.ProductFindOptions) (*commonmodels.Product, error) { + if opt == nil { + return nil, fmt.Errorf("product find options cannot be nil") + } + + key := productCacheKey(opt) + now := productNow() + if cached, ok := productCache.Load(key); ok { + item, ok := cached.(*productCacheItem) + if ok && now.Before(item.expireAt) { + return cloneProduct(item.product) + } + // 过期缓存立即删除,避免后续请求继续命中旧值。 + productCache.Delete(key) + } + + product, err := loadProductFunc(opt) + if err != nil || product == nil { + return product, err + } + + cachedProduct, err := cloneProduct(product) + if err != nil { + return nil, err + } + + productCache.Store(key, &productCacheItem{ + product: cachedProduct, + expireAt: now.Add(productCacheTTL), + }) + + return cloneProduct(cachedProduct) +} + +// productCacheKey 将 product 查询条件编码成缓存 key。 +// 这里把 Production 一并纳入 key,避免不同环境类型读到错误缓存。 +func productCacheKey(opt *commonrepo.ProductFindOptions) string { + production := "nil" + if opt != nil && opt.Production != nil { + production = fmt.Sprintf("%t", *opt.Production) + } + + return fmt.Sprintf("%s:%s:%s:%s", opt.Name, opt.EnvName, opt.Namespace, production) +} + +// cloneProduct 返回 product 的深拷贝。 +// 缓存层和业务层不共享同一个指针,避免调用方改值后污染缓存。 +func cloneProduct(product *commonmodels.Product) (*commonmodels.Product, error) { + if product == nil { + return nil, nil + } + + cloned := new(commonmodels.Product) + if err := util.DeepCopy(cloned, product); err != nil { + return nil, err + } + return cloned, nil +} + +// InvalidateProductCache 主动删除指定 key 的缓存。 +// 适合在环境更新、配置变更等写路径成功后调用,进一步缩短脏数据窗口。 +// func InvalidateProductCache(opt *commonrepo.ProductFindOptions) { +// if opt == nil { +// return +// } +// productCache.Delete(productCacheKey(opt)) +// } diff --git a/pkg/microservice/aslan/core/common/service/kube/render.go b/pkg/microservice/aslan/core/common/service/kube/render.go index 97f54a9b42..02e818c6fe 100644 --- a/pkg/microservice/aslan/core/common/service/kube/render.go +++ b/pkg/microservice/aslan/core/common/service/kube/render.go @@ -377,7 +377,7 @@ func FetchCurrentAppliedYaml(option *GeneSvcYamlOption) (string, int, error) { return "", 0, errors.Wrapf(err, "failed to find template product %s", option.ProductName) } - productInfo, err := commonrepo.NewProductColl().Find(&commonrepo.ProductFindOptions{ + productInfo, err := GetProductWithCache(&commonrepo.ProductFindOptions{ EnvName: option.EnvName, Name: option.ProductName, }) @@ -762,7 +762,7 @@ func GenerateRenderedYaml(option *GeneSvcYamlOption) (string, int, []*WorkloadRe return "", 0, nil, errors.Wrapf(err, "failed to find template product %s", option.ProductName) } - productInfo, err := commonrepo.NewProductColl().Find(&commonrepo.ProductFindOptions{ + productInfo, err := GetProductWithCache(&commonrepo.ProductFindOptions{ EnvName: option.EnvName, Name: option.ProductName, }) diff --git a/pkg/microservice/aslan/core/environment/service/configmap.go b/pkg/microservice/aslan/core/environment/service/configmap.go index f0eae28c0e..d3136f023a 100644 --- a/pkg/microservice/aslan/core/environment/service/configmap.go +++ b/pkg/microservice/aslan/core/environment/service/configmap.go @@ -85,7 +85,7 @@ func ListConfigMaps(args *ListConfigMapArgs, log *zap.SugaredLogger) ([]*ListCon selector = labels.Set{setting.ProductLabel: args.ProductName, setting.ServiceLabel: args.ServiceName}.AsSelector() } - product, err := commonrepo.NewProductColl().Find(&commonrepo.ProductFindOptions{ + product, err := kube.GetProductWithCache(&commonrepo.ProductFindOptions{ Name: args.ProductName, EnvName: args.EnvName, Production: &args.Production, @@ -195,7 +195,7 @@ func UpdateConfigMap(args *models.CreateUpdateCommonEnvCfgArgs, userName string, if cm.Name != args.Name { return e.ErrUpdateConfigMap.AddDesc("configMap Yaml Name is incorrect") } - product, err := commonrepo.NewProductColl().Find(&commonrepo.ProductFindOptions{ + product, err := kube.GetProductWithCache(&commonrepo.ProductFindOptions{ Name: args.ProductName, EnvName: args.EnvName, Production: &args.Production, @@ -257,7 +257,7 @@ func UpdateConfigMap(args *models.CreateUpdateCommonEnvCfgArgs, userName string, } func RollBackConfigMap(envName string, args *RollBackConfigMapArgs, userName, userID string, log *zap.SugaredLogger) error { - product, err := commonrepo.NewProductColl().Find(&commonrepo.ProductFindOptions{ + product, err := kube.GetProductWithCache(&commonrepo.ProductFindOptions{ Name: args.ProductName, EnvName: args.EnvName, Production: &args.Production, From 9c658f3a0a4bae9b0ea8d146e587971704464c4d Mon Sep 17 00:00:00 2001 From: YuTang Song <2313186065@qq.com> Date: Fri, 22 May 2026 17:54:10 +0800 Subject: [PATCH 5/5] fix: read data from mongodb Signed-off-by: YuTang Song <2313186065@qq.com> --- .../core/common/service/kube/product_cache.go | 96 ------------------- .../aslan/core/common/service/kube/render.go | 4 +- .../core/environment/service/configmap.go | 6 +- 3 files changed, 5 insertions(+), 101 deletions(-) delete mode 100644 pkg/microservice/aslan/core/common/service/kube/product_cache.go diff --git a/pkg/microservice/aslan/core/common/service/kube/product_cache.go b/pkg/microservice/aslan/core/common/service/kube/product_cache.go deleted file mode 100644 index 5de53a429a..0000000000 --- a/pkg/microservice/aslan/core/common/service/kube/product_cache.go +++ /dev/null @@ -1,96 +0,0 @@ -package kube - -import ( - "fmt" - "sync" - "time" - - commonmodels "github.com/koderover/zadig/v2/pkg/microservice/aslan/core/common/repository/models" - commonrepo "github.com/koderover/zadig/v2/pkg/microservice/aslan/core/common/repository/mongodb" - "github.com/koderover/zadig/v2/pkg/util" -) - -type productCacheItem struct { - product *commonmodels.Product - expireAt time.Time -} - -var ( - productCache sync.Map - productCacheTTL = 30 * time.Second - productNow = time.Now - loadProductFunc = func(opt *commonrepo.ProductFindOptions) (*commonmodels.Product, error) { - return commonrepo.NewProductColl().Find(opt) - } -) - -// GetProductWithCache 优先从内存缓存读取 product 元数据。 -// 如果缓存未命中或已过期,则重新查库并刷新缓存。 -// 返回值始终是深拷贝,避免调用方修改缓存中的原始对象。 -func GetProductWithCache(opt *commonrepo.ProductFindOptions) (*commonmodels.Product, error) { - if opt == nil { - return nil, fmt.Errorf("product find options cannot be nil") - } - - key := productCacheKey(opt) - now := productNow() - if cached, ok := productCache.Load(key); ok { - item, ok := cached.(*productCacheItem) - if ok && now.Before(item.expireAt) { - return cloneProduct(item.product) - } - // 过期缓存立即删除,避免后续请求继续命中旧值。 - productCache.Delete(key) - } - - product, err := loadProductFunc(opt) - if err != nil || product == nil { - return product, err - } - - cachedProduct, err := cloneProduct(product) - if err != nil { - return nil, err - } - - productCache.Store(key, &productCacheItem{ - product: cachedProduct, - expireAt: now.Add(productCacheTTL), - }) - - return cloneProduct(cachedProduct) -} - -// productCacheKey 将 product 查询条件编码成缓存 key。 -// 这里把 Production 一并纳入 key,避免不同环境类型读到错误缓存。 -func productCacheKey(opt *commonrepo.ProductFindOptions) string { - production := "nil" - if opt != nil && opt.Production != nil { - production = fmt.Sprintf("%t", *opt.Production) - } - - return fmt.Sprintf("%s:%s:%s:%s", opt.Name, opt.EnvName, opt.Namespace, production) -} - -// cloneProduct 返回 product 的深拷贝。 -// 缓存层和业务层不共享同一个指针,避免调用方改值后污染缓存。 -func cloneProduct(product *commonmodels.Product) (*commonmodels.Product, error) { - if product == nil { - return nil, nil - } - - cloned := new(commonmodels.Product) - if err := util.DeepCopy(cloned, product); err != nil { - return nil, err - } - return cloned, nil -} - -// InvalidateProductCache 主动删除指定 key 的缓存。 -// 适合在环境更新、配置变更等写路径成功后调用,进一步缩短脏数据窗口。 -// func InvalidateProductCache(opt *commonrepo.ProductFindOptions) { -// if opt == nil { -// return -// } -// productCache.Delete(productCacheKey(opt)) -// } diff --git a/pkg/microservice/aslan/core/common/service/kube/render.go b/pkg/microservice/aslan/core/common/service/kube/render.go index 02e818c6fe..97f54a9b42 100644 --- a/pkg/microservice/aslan/core/common/service/kube/render.go +++ b/pkg/microservice/aslan/core/common/service/kube/render.go @@ -377,7 +377,7 @@ func FetchCurrentAppliedYaml(option *GeneSvcYamlOption) (string, int, error) { return "", 0, errors.Wrapf(err, "failed to find template product %s", option.ProductName) } - productInfo, err := GetProductWithCache(&commonrepo.ProductFindOptions{ + productInfo, err := commonrepo.NewProductColl().Find(&commonrepo.ProductFindOptions{ EnvName: option.EnvName, Name: option.ProductName, }) @@ -762,7 +762,7 @@ func GenerateRenderedYaml(option *GeneSvcYamlOption) (string, int, []*WorkloadRe return "", 0, nil, errors.Wrapf(err, "failed to find template product %s", option.ProductName) } - productInfo, err := GetProductWithCache(&commonrepo.ProductFindOptions{ + productInfo, err := commonrepo.NewProductColl().Find(&commonrepo.ProductFindOptions{ EnvName: option.EnvName, Name: option.ProductName, }) diff --git a/pkg/microservice/aslan/core/environment/service/configmap.go b/pkg/microservice/aslan/core/environment/service/configmap.go index d3136f023a..f0eae28c0e 100644 --- a/pkg/microservice/aslan/core/environment/service/configmap.go +++ b/pkg/microservice/aslan/core/environment/service/configmap.go @@ -85,7 +85,7 @@ func ListConfigMaps(args *ListConfigMapArgs, log *zap.SugaredLogger) ([]*ListCon selector = labels.Set{setting.ProductLabel: args.ProductName, setting.ServiceLabel: args.ServiceName}.AsSelector() } - product, err := kube.GetProductWithCache(&commonrepo.ProductFindOptions{ + product, err := commonrepo.NewProductColl().Find(&commonrepo.ProductFindOptions{ Name: args.ProductName, EnvName: args.EnvName, Production: &args.Production, @@ -195,7 +195,7 @@ func UpdateConfigMap(args *models.CreateUpdateCommonEnvCfgArgs, userName string, if cm.Name != args.Name { return e.ErrUpdateConfigMap.AddDesc("configMap Yaml Name is incorrect") } - product, err := kube.GetProductWithCache(&commonrepo.ProductFindOptions{ + product, err := commonrepo.NewProductColl().Find(&commonrepo.ProductFindOptions{ Name: args.ProductName, EnvName: args.EnvName, Production: &args.Production, @@ -257,7 +257,7 @@ func UpdateConfigMap(args *models.CreateUpdateCommonEnvCfgArgs, userName string, } func RollBackConfigMap(envName string, args *RollBackConfigMapArgs, userName, userID string, log *zap.SugaredLogger) error { - product, err := kube.GetProductWithCache(&commonrepo.ProductFindOptions{ + product, err := commonrepo.NewProductColl().Find(&commonrepo.ProductFindOptions{ Name: args.ProductName, EnvName: args.EnvName, Production: &args.Production,