Files
app-api/internal/cache/curve_cache.go
T
eafonyang c4cd8b6f5d feat(equalize): 添加目标曲线获取及缓存功能
- 新增CurveCache实现Redis曲线数据缓存与分布式锁机制,避免重复请求
- 增加CurveHandler支持目标曲线接口,通过EQ API获取并缓存曲线数据
- Config新增EqualizeConfig配置,支持环境变量动态配置
- Repository新增CurveRepository,按brand和name查询模型与目标曲线数据
- 路由更新,集成/getCurve接口处理目标曲线请求
- OTA模型字段优化,bool类型改为BoolInt,实现数据库int与JSON bool映射
- 统一响应格式,调整response包中OK和Fail函数消息字段命名
- 修改服务端配置默认DB IP,支持Equalize参数传递到路由层
- 新增CSV解析实现,从文件读取测量与目标曲线数据
- 修改OTA处理逻辑,修复定向升级判断bug
- Java层新增EqualizeController和ModelService对应功能,保持客户端接口兼容与调用逻辑一致
2026-06-01 19:08:43 +08:00

88 lines
2.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package cache
import (
"context"
"fmt"
"time"
"github.com/redis/go-redis/v9"
)
const (
curveLockTTL = 10 * time.Second
curveLockRetryDelay = 100 * time.Millisecond
curveLockMaxRetries = 50
)
// CurveCache 曲线数据缓存(Redis Hash
type CurveCache struct {
rdb *redis.Client
}
func NewCurveCache(rdb *redis.Client) *CurveCache {
return &CurveCache{rdb: rdb}
}
// Get 从 Redis Hash 中获取曲线缓存
func (c *CurveCache) Get(ctx context.Context, brand, name, target string) (string, error) {
key := brand + " " + name
val, err := c.rdb.HGet(ctx, key, target).Result()
if err == redis.Nil {
return "", nil
}
if err != nil {
return "", fmt.Errorf("hget curve cache: %w", err)
}
return val, nil
}
// Set 将曲线数据存入 Redis Hash
func (c *CurveCache) Set(ctx context.Context, brand, name, target, data string) error {
key := brand + " " + name
return c.rdb.HSet(ctx, key, target, data).Err()
}
// AcquireLock 获取分布式锁(SETNX),防止并发请求同一个曲线数据
func (c *CurveCache) AcquireLock(ctx context.Context, brand, name, target string) (bool, error) {
lockKey := brand + " " + name + ":" + target + ":lock"
return c.rdb.SetNX(ctx, lockKey, "locked", curveLockTTL).Result()
}
// ReleaseLock 释放分布式锁
func (c *CurveCache) ReleaseLock(ctx context.Context, brand, name, target string) error {
lockKey := brand + " " + name + ":" + target + ":lock"
return c.rdb.Del(ctx, lockKey).Err()
}
// GetWithLock 获取缓存数据,缓存不存在时尝试加锁后重新获取
// 返回值: (data, acquired, error)
// - data: 缓存数据(空字符串表示无数据)
// - acquired: 是否成功获取锁(缓存不存在时需要加锁)
func (c *CurveCache) GetWithLock(ctx context.Context, brand, name, target string) (data string, acquired bool, err error) {
// 先查缓存
data, err = c.Get(ctx, brand, name, target)
if err != nil {
return "", false, err
}
if data != "" {
return data, false, nil // 缓存命中
}
// 缓存不存在,尝试加锁
acquired, err = c.AcquireLock(ctx, brand, name, target)
if err != nil {
return "", false, fmt.Errorf("acquire curve lock: %w", err)
}
if acquired {
// 加锁成功,再次检查缓存(双重检查)
data, err = c.Get(ctx, brand, name, target)
if err != nil {
return "", true, err
}
return data, true, nil
}
// 未获取锁,等待后重试
return "", false, nil
}