package aeusadmin import ( "context" "time" "git.nobla.cn/golang/aeus/pkg/cache" "gorm.io/gorm" ) type ( CachingFunc func(tx *gorm.DB) (any, error) CacheOptions struct { db *gorm.DB cache cache.Cache dependSQL string dependArgs []any cacheDuration time.Duration } CacheOption func(o *CacheOptions) cacheEntry struct { storeValue any compareValue string createdAt time.Time lastChecked time.Time } ) func WithDepend(s string, args ...any) CacheOption { return func(o *CacheOptions) { o.dependSQL = s o.dependArgs = args } } func TryCache(ctx context.Context, key string, f CachingFunc, cbs ...CacheOption) (value any, err error) { var ( hasDependValue bool dependValue string ) opts := &CacheOptions{ cacheDuration: time.Minute * 10, } for _, cb := range cbs { cb(opts) } //从缓存加载数据 if value, _, err = opts.cache.Get(ctx, key); err == nil { entry := value.(*cacheEntry) if opts.dependSQL == "" { return entry.storeValue, nil } //如果频繁访问,不检查依赖 if time.Since(entry.lastChecked) < time.Millisecond*500 { return entry.storeValue, nil } //对比依赖值 if err = opts.db.Raw(opts.dependSQL, opts.dependArgs...).Scan(&dependValue).Error; err == nil { hasDependValue = true if entry.compareValue == dependValue { entry.lastChecked = time.Now() return entry.storeValue, nil } else { opts.cache.Delete(ctx, key) } } } //从数据库加载数据 if value, err = f(opts.db.WithContext(ctx)); err == nil { if !hasDependValue { if err = opts.db.WithContext(ctx).Raw(opts.dependSQL, opts.dependArgs...).Scan(&dependValue).Error; err == nil { opts.cache.Put(ctx, key, &cacheEntry{ compareValue: dependValue, storeValue: value, createdAt: time.Now(), lastChecked: time.Now(), }, opts.cacheDuration) } } else { opts.cache.Put(ctx, key, &cacheEntry{ compareValue: dependValue, storeValue: value, createdAt: time.Now(), lastChecked: time.Now(), }, opts.cacheDuration) } return value, nil } else { return nil, err } }