- 封装缓存读写、JSON 编解码、过期时间与操作超时 - 集中组装 Redis 依赖,在测试接口验证分类缓存读写 - 更新依赖并移除原 handler 测试 BREAKING CHANGE: 配置节由 redis 改为 cache,新增 db 和 timeout 配置项
69 lines
1.6 KiB
Go
69 lines
1.6 KiB
Go
package cache
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json/v2"
|
|
"errors"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/redis/go-redis/v9"
|
|
)
|
|
|
|
type Entry[T any] struct {
|
|
Key string
|
|
Value T
|
|
TTL time.Duration
|
|
}
|
|
|
|
type Cache struct {
|
|
client *redis.Client
|
|
operationTimeout time.Duration
|
|
}
|
|
|
|
func NewCache(client *redis.Client, timeout time.Duration) *Cache {
|
|
return &Cache{
|
|
client: client,
|
|
operationTimeout: timeout,
|
|
}
|
|
}
|
|
|
|
func (c *Cache) Get[T any](ctx context.Context, key string) (T, bool, error) {
|
|
var zero T
|
|
operationCtx, cancel := context.WithTimeout(ctx, c.operationTimeout)
|
|
defer cancel()
|
|
|
|
payload, err := c.client.Get(operationCtx, key).Result()
|
|
cancel()
|
|
if errors.Is(err, redis.Nil) {
|
|
return zero, false, nil
|
|
}
|
|
if err != nil {
|
|
return zero, false, fmt.Errorf("读取缓存失败:%w", err)
|
|
}
|
|
var value T
|
|
if err := json.Unmarshal([]byte(payload), &value); err != nil {
|
|
return zero, false, fmt.Errorf("缓存解码失败:%w", err)
|
|
}
|
|
return value, true, nil
|
|
}
|
|
|
|
func (c *Cache) Set[T any](ctx context.Context, entry Entry[T]) error {
|
|
if entry.TTL < 0 {
|
|
return fmt.Errorf("缓存过期时间必须大于等于零: %v", entry.TTL)
|
|
}
|
|
if err := ctx.Err(); err != nil {
|
|
return fmt.Errorf("写入缓存失败:%w", err)
|
|
}
|
|
payload, err := json.Marshal(entry.Value)
|
|
if err != nil {
|
|
return fmt.Errorf("缓存编码失败:%w", err)
|
|
}
|
|
operationCtx, cancel := context.WithTimeout(ctx, c.operationTimeout)
|
|
defer cancel()
|
|
if err := c.client.Set(operationCtx, entry.Key, payload, entry.TTL).Err(); err != nil {
|
|
return fmt.Errorf("写入缓存失败:%w", err)
|
|
}
|
|
return nil
|
|
}
|