From bdd2dfcd8413b83115b0e511bfdb04e1e88a1a46 Mon Sep 17 00:00:00 2001 From: caadiq Date: Fri, 23 Jan 2026 22:04:27 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EC=84=B1=EB=8A=A5=20=EC=B5=9C=EC=A0=81?= =?UTF-8?q?=ED=99=94=20(Phase=204)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - cache.js: Redis KEYS → SCAN으로 변경 (블로킹 방지) - suggestions.js: 동기식 파일 I/O → 비동기 변경 - readFileSync → readFile (fs/promises) - writeFileSync → writeFile (fs/promises) - improvements.md: Phase 4 완료로 업데이트 Co-Authored-By: Claude Opus 4.5 --- backend/src/routes/schedules/suggestions.js | 6 +++--- backend/src/utils/cache.js | 14 +++++++++----- docs/improvements.md | 6 +++--- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/backend/src/routes/schedules/suggestions.js b/backend/src/routes/schedules/suggestions.js index 1c9f00d..0a4f2a0 100644 --- a/backend/src/routes/schedules/suggestions.js +++ b/backend/src/routes/schedules/suggestions.js @@ -1,7 +1,7 @@ /** * 추천 검색어 API 라우트 */ -import { readFileSync, writeFileSync } from 'fs'; +import { readFile, writeFile } from 'fs/promises'; import { SuggestionService } from '../../services/suggestions/index.js'; import { reloadMorpheme, getUserDictPath } from '../../services/suggestions/morpheme.js'; import { badRequest, serverError } from '../../utils/error.js'; @@ -139,7 +139,7 @@ export default async function suggestionsRoutes(fastify) { }, async (request, reply) => { try { const dictPath = getUserDictPath(); - const content = readFileSync(dictPath, 'utf-8'); + const content = await readFile(dictPath, 'utf-8'); return { content }; } catch (error) { if (error.code === 'ENOENT') { @@ -180,7 +180,7 @@ export default async function suggestionsRoutes(fastify) { try { const dictPath = getUserDictPath(); - writeFileSync(dictPath, content, 'utf-8'); + await writeFile(dictPath, content, 'utf-8'); // 형태소 분석기 리로드 await reloadMorpheme(); diff --git a/backend/src/utils/cache.js b/backend/src/utils/cache.js index db30612..185c0d4 100644 --- a/backend/src/utils/cache.js +++ b/backend/src/utils/cache.js @@ -41,15 +41,19 @@ export async function invalidate(redis, keys) { } /** - * 패턴으로 캐시 무효화 + * 패턴으로 캐시 무효화 (SCAN 사용으로 블로킹 방지) * @param {object} redis - Redis 클라이언트 * @param {string} pattern - 키 패턴 (예: 'schedule:*') */ export async function invalidatePattern(redis, pattern) { - const keys = await redis.keys(pattern); - if (keys.length > 0) { - await redis.del(...keys); - } + let cursor = '0'; + do { + const [nextCursor, keys] = await redis.scan(cursor, 'MATCH', pattern, 'COUNT', 100); + cursor = nextCursor; + if (keys.length > 0) { + await redis.del(...keys); + } + } while (cursor !== '0'); } // 캐시 키 생성 헬퍼 diff --git a/docs/improvements.md b/docs/improvements.md index 1c971c3..faba54a 100644 --- a/docs/improvements.md +++ b/docs/improvements.md @@ -546,8 +546,8 @@ await writeFile(dictPath, content, 'utf-8'); | 이슈 | 우선순위 | 상태 | |------|---------|------| -| Redis KEYS → SCAN | Low | ⬜ 미해결 | -| 동기식 파일 I/O | Low | ⬜ 미해결 | +| Redis KEYS → SCAN | Low | ✅ 해결됨 | +| 동기식 파일 I/O | Low | ✅ 해결됨 | --- @@ -560,4 +560,4 @@ await writeFile(dictPath, content, 'utf-8'); --- -*마지막 업데이트: 2025-01* +*마지막 업데이트: 2026-01-23*