aeus-admin/cache.go

94 lines
2.1 KiB
Go

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
}
}