91 lines
2.7 KiB
Go
91 lines
2.7 KiB
Go
package lib
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"log"
|
|
"time"
|
|
|
|
"github.com/redis/go-redis/v9"
|
|
)
|
|
|
|
// RedisStorage implements a Redis-backed caching layer for test data.
|
|
// It provides fast access to frequently requested data while reducing database load.
|
|
type RedisStorage struct {
|
|
client *redis.Client
|
|
}
|
|
|
|
// NewRedisStorage creates and initializes a new Redis connection with the provided URL.
|
|
// It verifies the connection and configures default timeouts.
|
|
func NewRedisStorage(url string) (*RedisStorage, error) {
|
|
opt, err := redis.ParseURL(url)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to parse Redis URL: %v", err)
|
|
}
|
|
|
|
client := redis.NewClient(opt)
|
|
|
|
// Verify connection is working
|
|
ctx := context.Background()
|
|
if err := client.Ping(ctx).Err(); err != nil {
|
|
return nil, fmt.Errorf("failed to connect to Redis: %v", err)
|
|
}
|
|
|
|
log.Printf("Successfully connected to Redis")
|
|
return &RedisStorage{client: client}, nil
|
|
}
|
|
|
|
// GetTestData retrieves cached test data if available.
|
|
// Returns (nil, redis.Nil) if key doesn't exist.
|
|
func (s *RedisStorage) GetTestData(ctx context.Context) (*TestData, error) {
|
|
data, err := s.client.Get(ctx, "test_data").Bytes()
|
|
if err != nil {
|
|
if err == redis.Nil {
|
|
log.Printf("Redis: Cache miss - key not found")
|
|
} else {
|
|
log.Printf("Redis: Error retrieving data: %v", err)
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
var testData TestData
|
|
if err := json.Unmarshal(data, &testData); err != nil {
|
|
log.Printf("Redis: Error deserializing cached data: %v", err)
|
|
return nil, err
|
|
}
|
|
|
|
log.Printf("Redis: Cache hit - retrieved data: %+v", testData)
|
|
return &testData, nil
|
|
}
|
|
|
|
// SaveTestData caches the provided test data with a 1-hour TTL.
|
|
// Existing data for the same key will be overwritten.
|
|
func (s *RedisStorage) SaveTestData(ctx context.Context, data *TestData) error {
|
|
jsonData, err := json.Marshal(data)
|
|
if err != nil {
|
|
log.Printf("Redis: Error serializing data: %v", err)
|
|
return err
|
|
}
|
|
|
|
err = s.client.Set(ctx, "test_data", jsonData, 1*time.Hour).Err()
|
|
if err != nil {
|
|
log.Printf("Redis: Error writing to cache: %v", err)
|
|
return err
|
|
}
|
|
|
|
log.Printf("Redis: Successfully cached data: %+v", data)
|
|
return nil
|
|
}
|
|
|
|
// InvalidateTestData removes the test data from cache.
|
|
// This is typically called when the underlying data is updated.
|
|
func (s *RedisStorage) InvalidateTestData(ctx context.Context) error {
|
|
err := s.client.Del(ctx, "test_data").Err()
|
|
if err != nil {
|
|
log.Printf("Redis: Error invalidating cache: %v", err)
|
|
} else {
|
|
log.Printf("Redis: Successfully invalidated cached data")
|
|
}
|
|
return err
|
|
}
|