topfans/backend/services/statisticService/service/cache.go
zerosaturation dd9952ccc9 feat(statistic): T9-T12 dashboard 7 RPCs (Provider + Materializer + Service + Cache)
- StatisticInternalProvider: TrackEvent/BatchTrackEvent
- StatisticCombinedProvider: all 9 RPCs (7 dashboard + 2 event) on single service
- materializer: 4 MV REFRESH CONCURRENTLY + pg_try_advisory_lock + refresh_log
- dashboard_repo: 7 aggregation SQLs (week_rank / 7d curve / top5 / level dist / upgrade progress)
- dashboard_service: 7 RPCs with Redis 5min TTL + cache miss protection (1min empty)
- Cache wrapper: JSON serialize + format dash:{rpc}:{starID}:{userID}
- main.go: integrated workers + Dubbo triple server :20009
- cross-service userService.GetFanProfile (for crystal_balance)
- client/user_rpc_client.go

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 17:20:53 +08:00

65 lines
1.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 service
import (
"context"
"encoding/json"
"fmt"
"time"
"github.com/redis/go-redis/v9"
)
// Cache Redis 缓存封装5min TTL + 1min 空值 TTL 防穿透)
type Cache struct {
rdb *redis.Client
ttl time.Duration
emptyTTL time.Duration
missedHits int64
}
// NewCache 构造
func NewCache(rdb *redis.Client) *Cache {
return &Cache{
rdb: rdb,
ttl: 5 * time.Minute,
emptyTTL: 1 * time.Minute,
}
}
// GetJSON 取缓存 + JSON 反序列化
func (c *Cache) GetJSON(ctx context.Context, key string, dst interface{}) (bool, error) {
v, err := c.rdb.Get(ctx, key).Result()
if err == redis.Nil {
return false, nil
}
if err != nil {
return false, err
}
if v == "null" {
return false, nil // 缓存穿透防护的空标记
}
if err := json.Unmarshal([]byte(v), dst); err != nil {
return false, err
}
return true, nil
}
// SetJSON 序列化 + 缓存5min TTL
func (c *Cache) SetJSON(ctx context.Context, key string, value interface{}) error {
b, err := json.Marshal(value)
if err != nil {
return err
}
return c.rdb.Set(ctx, key, b, c.ttl).Err()
}
// SetEmpty 缓存空值1min TTL防穿透
func (c *Cache) SetEmpty(ctx context.Context, key string) error {
return c.rdb.Set(ctx, key, "null", c.emptyTTL).Err()
}
// CacheKey 看板缓存 key 格式
func CacheKey(rpc string, starID, userID int64) string {
return fmt.Sprintf("dash:%s:%d:%d", rpc, starID, userID)
}