94 lines
2.1 KiB
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
|
|
}
|
|
}
|