github.com/argoproj/argo-cd/v3@v3.2.1/util/cache/appstate/cache.go (about) 1 package appstate 2 3 import ( 4 "context" 5 "fmt" 6 "sort" 7 "time" 8 9 "github.com/spf13/cobra" 10 11 appv1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1" 12 cacheutil "github.com/argoproj/argo-cd/v3/util/cache" 13 "github.com/argoproj/argo-cd/v3/util/env" 14 ) 15 16 var ( 17 ErrCacheMiss = cacheutil.ErrCacheMiss 18 treeShardSize = env.ParseInt64FromEnv("ARGOCD_APPLICATION_TREE_SHARD_SIZE", 0, 0, 1000) 19 ) 20 21 const ( 22 clusterInfoCacheExpiration = 10 * time.Minute 23 ) 24 25 type Cache struct { 26 Cache *cacheutil.Cache 27 appStateCacheExpiration time.Duration 28 } 29 30 func NewCache(cache *cacheutil.Cache, appStateCacheExpiration time.Duration) *Cache { 31 return &Cache{cache, appStateCacheExpiration} 32 } 33 34 func AddCacheFlagsToCmd(cmd *cobra.Command, opts ...cacheutil.Options) func() (*Cache, error) { 35 var appStateCacheExpiration time.Duration 36 37 cmd.Flags().DurationVar(&appStateCacheExpiration, "app-state-cache-expiration", env.ParseDurationFromEnv("ARGOCD_APP_STATE_CACHE_EXPIRATION", 1*time.Hour, 0, 10*time.Hour), "Cache expiration for app state") 38 39 cacheFactory := cacheutil.AddCacheFlagsToCmd(cmd, opts...) 40 41 return func() (*Cache, error) { 42 cache, err := cacheFactory() 43 if err != nil { 44 return nil, err 45 } 46 return NewCache(cache, appStateCacheExpiration), nil 47 } 48 } 49 50 func (c *Cache) GetItem(key string, item any) error { 51 return c.Cache.GetItem(key, item) 52 } 53 54 func (c *Cache) SetItem(key string, item any, expiration time.Duration, deletion bool) error { 55 return c.Cache.SetItem(key, item, &cacheutil.CacheActionOpts{Expiration: expiration, Delete: deletion}) 56 } 57 58 func appManagedResourcesKey(appName string) string { 59 return "app|managed-resources|" + appName 60 } 61 62 func (c *Cache) GetAppManagedResources(appName string, res *[]*appv1.ResourceDiff) error { 63 err := c.GetItem(appManagedResourcesKey(appName), &res) 64 return err 65 } 66 67 func (c *Cache) SetAppManagedResources(appName string, managedResources []*appv1.ResourceDiff) error { 68 sort.Slice(managedResources, func(i, j int) bool { 69 return managedResources[i].FullName() < managedResources[j].FullName() 70 }) 71 return c.SetItem(appManagedResourcesKey(appName), managedResources, c.appStateCacheExpiration, managedResources == nil) 72 } 73 74 func appResourcesTreeKey(appName string, shard int64) string { 75 key := "app|resources-tree|" + appName 76 if shard > 0 { 77 key = fmt.Sprintf("%s|%d", key, shard) 78 } 79 return key 80 } 81 82 func clusterInfoKey(server string) string { 83 return "cluster|info|" + server 84 } 85 86 func (c *Cache) GetAppResourcesTree(appName string, res *appv1.ApplicationTree) error { 87 err := c.GetItem(appResourcesTreeKey(appName, 0), &res) 88 if res.ShardsCount > 1 { 89 for i := int64(1); i < res.ShardsCount; i++ { 90 var shard appv1.ApplicationTree 91 err = c.GetItem(appResourcesTreeKey(appName, i), &shard) 92 if err != nil { 93 return err 94 } 95 res.Merge(&shard) 96 } 97 } 98 return err 99 } 100 101 func (c *Cache) OnAppResourcesTreeChanged(ctx context.Context, appName string, callback func() error) error { 102 return c.Cache.OnUpdated(ctx, appManagedResourcesKey(appName), callback) 103 } 104 105 func (c *Cache) SetAppResourcesTree(appName string, resourcesTree *appv1.ApplicationTree) error { 106 if resourcesTree == nil { 107 if err := c.SetItem(appResourcesTreeKey(appName, 0), resourcesTree, c.appStateCacheExpiration, true); err != nil { 108 return err 109 } 110 } else { 111 // Splitting resource tree into shards reduces number of Redis SET calls and therefore amount of traffic sent 112 // from controller to Redis. Controller still stores each shard in cache but util/cache/twolevelclient.go 113 // forwards request to Redis only if shard actually changes. 114 for i, shard := range resourcesTree.GetShards(treeShardSize) { 115 if err := c.SetItem(appResourcesTreeKey(appName, int64(i)), shard, c.appStateCacheExpiration, false); err != nil { 116 return err 117 } 118 } 119 } 120 121 return c.Cache.NotifyUpdated(appManagedResourcesKey(appName)) 122 } 123 124 func (c *Cache) SetClusterInfo(server string, info *appv1.ClusterInfo) error { 125 return c.SetItem(clusterInfoKey(server), info, clusterInfoCacheExpiration, info == nil) 126 } 127 128 func (c *Cache) GetClusterInfo(server string, res *appv1.ClusterInfo) error { 129 err := c.GetItem(clusterInfoKey(server), &res) 130 return err 131 }