69 lines
1.5 KiB
Go
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()
|
|
}
|
|
}
|