mirror of
https://github.com/SamyRai/tercul-backend.git
synced 2025-12-27 05:11:34 +00:00
199 lines
4.9 KiB
Go
199 lines
4.9 KiB
Go
package linguistics
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"github.com/hashicorp/golang-lru/v2"
|
|
"sync"
|
|
"tercul/internal/platform/cache"
|
|
"tercul/internal/platform/config"
|
|
"tercul/internal/platform/log"
|
|
"time"
|
|
)
|
|
|
|
// AnalysisCache defines the interface for caching analysis results
|
|
type AnalysisCache interface {
|
|
// Get retrieves cached analysis result
|
|
Get(ctx context.Context, key string) (*AnalysisResult, error)
|
|
|
|
// Set stores analysis result in cache
|
|
Set(ctx context.Context, key string, result *AnalysisResult) error
|
|
|
|
// IsEnabled returns whether caching is enabled
|
|
IsEnabled() bool
|
|
}
|
|
|
|
// MemoryAnalysisCache implements in-memory caching for analysis results
|
|
type MemoryAnalysisCache struct {
|
|
cache *lru.Cache[string, *AnalysisResult]
|
|
mutex sync.RWMutex
|
|
enabled bool
|
|
}
|
|
|
|
// NewMemoryAnalysisCache creates a new MemoryAnalysisCache
|
|
func NewMemoryAnalysisCache(enabled bool) *MemoryAnalysisCache {
|
|
// capacity from config
|
|
cap := config.Cfg.NLPMemoryCacheCap
|
|
if cap <= 0 {
|
|
cap = 1024
|
|
}
|
|
l, _ := lru.New[string, *AnalysisResult](cap)
|
|
return &MemoryAnalysisCache{
|
|
cache: l,
|
|
enabled: enabled,
|
|
}
|
|
}
|
|
|
|
// Get retrieves cached analysis result from memory
|
|
func (c *MemoryAnalysisCache) Get(ctx context.Context, key string) (*AnalysisResult, error) {
|
|
if !c.enabled {
|
|
return nil, fmt.Errorf("cache disabled")
|
|
}
|
|
|
|
c.mutex.RLock()
|
|
defer c.mutex.RUnlock()
|
|
|
|
if result, exists := c.cache.Get(key); exists {
|
|
return result, nil
|
|
}
|
|
|
|
return nil, fmt.Errorf("cache miss")
|
|
}
|
|
|
|
// Set stores analysis result in memory cache
|
|
func (c *MemoryAnalysisCache) Set(ctx context.Context, key string, result *AnalysisResult) error {
|
|
if !c.enabled {
|
|
return nil
|
|
}
|
|
|
|
c.mutex.Lock()
|
|
defer c.mutex.Unlock()
|
|
|
|
c.cache.Add(key, result)
|
|
return nil
|
|
}
|
|
|
|
// IsEnabled returns whether caching is enabled
|
|
func (c *MemoryAnalysisCache) IsEnabled() bool {
|
|
return c.enabled
|
|
}
|
|
|
|
// RedisAnalysisCache implements Redis-based caching for analysis results
|
|
type RedisAnalysisCache struct {
|
|
cache cache.Cache
|
|
enabled bool
|
|
}
|
|
|
|
// NewRedisAnalysisCache creates a new RedisAnalysisCache
|
|
func NewRedisAnalysisCache(cache cache.Cache, enabled bool) *RedisAnalysisCache {
|
|
return &RedisAnalysisCache{
|
|
cache: cache,
|
|
enabled: enabled,
|
|
}
|
|
}
|
|
|
|
// Get retrieves cached analysis result from Redis
|
|
func (c *RedisAnalysisCache) Get(ctx context.Context, key string) (*AnalysisResult, error) {
|
|
if !c.enabled || c.cache == nil {
|
|
return nil, fmt.Errorf("cache disabled or unavailable")
|
|
}
|
|
|
|
var result AnalysisResult
|
|
err := c.cache.Get(ctx, key, &result)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cache miss: %w", err)
|
|
}
|
|
|
|
return &result, nil
|
|
}
|
|
|
|
// Set stores analysis result in Redis cache
|
|
func (c *RedisAnalysisCache) Set(ctx context.Context, key string, result *AnalysisResult) error {
|
|
if !c.enabled || c.cache == nil {
|
|
return nil
|
|
}
|
|
|
|
// TTL from config
|
|
ttlSeconds := config.Cfg.NLPRedisCacheTTLSeconds
|
|
err := c.cache.Set(ctx, key, result, time.Duration(ttlSeconds)*time.Second)
|
|
if err != nil {
|
|
log.LogWarn("Failed to cache analysis result",
|
|
log.F("key", key),
|
|
log.F("error", err))
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// IsEnabled returns whether caching is enabled
|
|
func (c *RedisAnalysisCache) IsEnabled() bool {
|
|
return c.enabled && c.cache != nil
|
|
}
|
|
|
|
// CompositeAnalysisCache combines multiple cache layers
|
|
type CompositeAnalysisCache struct {
|
|
memoryCache AnalysisCache
|
|
redisCache AnalysisCache
|
|
enabled bool
|
|
}
|
|
|
|
// NewCompositeAnalysisCache creates a new CompositeAnalysisCache
|
|
func NewCompositeAnalysisCache(memoryCache AnalysisCache, redisCache AnalysisCache, enabled bool) *CompositeAnalysisCache {
|
|
return &CompositeAnalysisCache{
|
|
memoryCache: memoryCache,
|
|
redisCache: redisCache,
|
|
enabled: enabled,
|
|
}
|
|
}
|
|
|
|
// Get retrieves cached analysis result from memory first, then Redis
|
|
func (c *CompositeAnalysisCache) Get(ctx context.Context, key string) (*AnalysisResult, error) {
|
|
if !c.enabled {
|
|
return nil, fmt.Errorf("cache disabled")
|
|
}
|
|
|
|
// Try memory cache first
|
|
if result, err := c.memoryCache.Get(ctx, key); err == nil {
|
|
return result, nil
|
|
}
|
|
|
|
// Try Redis cache
|
|
if result, err := c.redisCache.Get(ctx, key); err == nil {
|
|
// Populate memory cache with Redis result
|
|
c.memoryCache.Set(ctx, key, result)
|
|
return result, nil
|
|
}
|
|
|
|
return nil, fmt.Errorf("cache miss")
|
|
}
|
|
|
|
// Set stores analysis result in both memory and Redis caches
|
|
func (c *CompositeAnalysisCache) Set(ctx context.Context, key string, result *AnalysisResult) error {
|
|
if !c.enabled {
|
|
return nil
|
|
}
|
|
|
|
// Set in memory cache
|
|
if err := c.memoryCache.Set(ctx, key, result); err != nil {
|
|
log.LogWarn("Failed to set memory cache",
|
|
log.F("key", key),
|
|
log.F("error", err))
|
|
}
|
|
|
|
// Set in Redis cache
|
|
if err := c.redisCache.Set(ctx, key, result); err != nil {
|
|
log.LogWarn("Failed to set Redis cache",
|
|
log.F("key", key),
|
|
log.F("error", err))
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// IsEnabled returns whether caching is enabled
|
|
func (c *CompositeAnalysisCache) IsEnabled() bool {
|
|
return c.enabled
|
|
}
|