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() } }