162 lines
3.8 KiB
TypeScript
162 lines
3.8 KiB
TypeScript
/**
|
|
* 공통 코드 캐시 시스템
|
|
* 자주 사용되는 공통 코드들을 메모리에 캐싱하여 성능을 향상시킵니다.
|
|
*/
|
|
|
|
import { commonCodeApi } from "@/lib/api/commonCode";
|
|
|
|
interface CacheEntry {
|
|
data: any;
|
|
timestamp: number;
|
|
expiry: number;
|
|
}
|
|
|
|
class CodeCache {
|
|
private cache = new Map<string, CacheEntry>();
|
|
private defaultTTL = 5 * 60 * 1000; // 5분
|
|
|
|
/**
|
|
* 캐시에 데이터 저장
|
|
*/
|
|
set(key: string, data: any, ttl?: number): void {
|
|
const expiry = ttl || this.defaultTTL;
|
|
const entry: CacheEntry = {
|
|
data,
|
|
timestamp: Date.now(),
|
|
expiry,
|
|
};
|
|
this.cache.set(key, entry);
|
|
}
|
|
|
|
/**
|
|
* 캐시에서 데이터 조회
|
|
*/
|
|
get(key: string): any | null {
|
|
const entry = this.cache.get(key);
|
|
if (!entry) {
|
|
return null;
|
|
}
|
|
|
|
// TTL 체크
|
|
if (Date.now() - entry.timestamp > entry.expiry) {
|
|
this.cache.delete(key);
|
|
return null;
|
|
}
|
|
|
|
return entry.data;
|
|
}
|
|
|
|
/**
|
|
* 캐시에서 데이터 삭제
|
|
*/
|
|
delete(key: string): boolean {
|
|
return this.cache.delete(key);
|
|
}
|
|
|
|
/**
|
|
* 모든 캐시 삭제
|
|
*/
|
|
clear(): void {
|
|
this.cache.clear();
|
|
}
|
|
|
|
/**
|
|
* 만료된 캐시 정리
|
|
*/
|
|
cleanup(): void {
|
|
const now = Date.now();
|
|
for (const [key, entry] of this.cache.entries()) {
|
|
if (now - entry.timestamp > entry.expiry) {
|
|
this.cache.delete(key);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 캐시 상태 조회
|
|
*/
|
|
getStats(): { size: number; keys: string[] } {
|
|
return {
|
|
size: this.cache.size,
|
|
keys: Array.from(this.cache.keys()),
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 공통 코드 캐시 키 생성
|
|
*/
|
|
createCodeKey(category: string, companyCode?: string): string {
|
|
return `code:${category}:${companyCode || "*"}`;
|
|
}
|
|
|
|
/**
|
|
* 여러 코드 카테고리를 배치로 미리 로딩
|
|
*/
|
|
async preloadCodes(categories: string[]): Promise<void> {
|
|
console.log(`🔄 코드 배치 로딩 시작: ${categories.join(", ")}`);
|
|
|
|
const promises = categories.map(async (category) => {
|
|
try {
|
|
const response = await commonCodeApi.codes.getList(category, { isActive: true });
|
|
if (response.success && response.data) {
|
|
const cacheKey = this.createCodeKey(category);
|
|
this.set(cacheKey, response.data, this.defaultTTL);
|
|
console.log(`✅ 코드 로딩 완료: ${category} (${response.data.length}개)`);
|
|
}
|
|
} catch (error) {
|
|
console.error(`❌ 코드 로딩 실패: ${category}`, error);
|
|
}
|
|
});
|
|
|
|
await Promise.all(promises);
|
|
console.log(`✅ 코드 배치 로딩 완료: ${categories.length}개 카테고리`);
|
|
}
|
|
|
|
/**
|
|
* 코드를 동기적으로 조회 (캐시에서만)
|
|
*/
|
|
getCodeSync(category: string, companyCode?: string): any[] | null {
|
|
const cacheKey = this.createCodeKey(category, companyCode);
|
|
return this.get(cacheKey);
|
|
}
|
|
|
|
/**
|
|
* 코드를 비동기적으로 조회 (캐시 미스 시 API 호출)
|
|
*/
|
|
async getCodeAsync(category: string, companyCode?: string): Promise<any[]> {
|
|
const cached = this.getCodeSync(category, companyCode);
|
|
if (cached) {
|
|
return cached;
|
|
}
|
|
|
|
try {
|
|
const response = await commonCodeApi.codes.getList(category, { isActive: true });
|
|
if (response.success && response.data) {
|
|
const cacheKey = this.createCodeKey(category, companyCode);
|
|
this.set(cacheKey, response.data, this.defaultTTL);
|
|
return response.data;
|
|
}
|
|
} catch (error) {
|
|
console.error(`❌ 코드 조회 실패: ${category}`, error);
|
|
}
|
|
|
|
return [];
|
|
}
|
|
}
|
|
|
|
// 싱글톤 인스턴스 생성
|
|
const codeCache = new CodeCache();
|
|
|
|
// 주기적으로 만료된 캐시 정리 (10분마다)
|
|
if (typeof window !== "undefined") {
|
|
setInterval(
|
|
() => {
|
|
codeCache.cleanup();
|
|
},
|
|
10 * 60 * 1000,
|
|
);
|
|
}
|
|
|
|
export default codeCache;
|
|
export { CodeCache, codeCache };
|