Files
stocksearch/services/cache_service.go
2026-03-31 19:32:59 +09:00

69 lines
1.5 KiB
Go

package services
import (
"sync"
"time"
)
// cacheItem 캐시 항목
type cacheItem struct {
value interface{}
expiresAt time.Time
}
// CacheService 인메모리 TTL 캐시
type CacheService struct {
mu sync.RWMutex
items map[string]*cacheItem
}
var cacheSvc *CacheService
var cacheOnce sync.Once
// GetCacheService 캐시 서비스 싱글턴 반환
func GetCacheService() *CacheService {
cacheOnce.Do(func() {
c := &CacheService{items: make(map[string]*cacheItem)}
go c.cleanup() // 만료 항목 주기적 정리
cacheSvc = c
})
return cacheSvc
}
// Set 캐시에 값 저장 (ttl: 유효기간)
func (c *CacheService) Set(key string, value interface{}, ttl time.Duration) {
c.mu.Lock()
defer c.mu.Unlock()
c.items[key] = &cacheItem{
value: value,
expiresAt: time.Now().Add(ttl),
}
}
// Get 캐시에서 값 조회. 없거나 만료됐으면 nil, false 반환
func (c *CacheService) Get(key string) (interface{}, bool) {
c.mu.RLock()
defer c.mu.RUnlock()
item, ok := c.items[key]
if !ok || time.Now().After(item.expiresAt) {
return nil, false
}
return item.value, true
}
// cleanup 만료된 캐시 항목을 주기적으로 삭제 (메모리 누수 방지)
func (c *CacheService) cleanup() {
ticker := time.NewTicker(30 * time.Second)
defer ticker.Stop()
for range ticker.C {
c.mu.Lock()
now := time.Now()
for key, item := range c.items {
if now.After(item.expiresAt) {
delete(c.items, key)
}
}
c.mu.Unlock()
}
}