8000 fix: 개선 전 조회 캐시를 무효화 by hmmhmmhm · Pull Request #226 · hmmhmmhm/daiso-mcp · GitHub
[go: up one dir, main page]

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/quality-improvements-2026-10-05.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,5 @@
수정 후 검증은 228개 파일·2,631개 테스트, `npm run check`, 100% Statements/Branches/Functions/Lines coverage, build, Worker dry run을 통과했습니다. 독립 리뷰에서 비교 결과 한도·GS25 미확인 합계·메타데이터의 잘못된 0·REST/MCP 빈 결과 차이를 찾아 추가 수정하고 재검증했습니다.

운영 확인은 배포 후 같은 상품 코드·매장·지역의 결과를 REST/MCP/공개 CLI로 확인해야 합니다. 정상 검색 결과만으로 모든 실패 경로가 정상이라는 결론을 내리지 않습니다. 편의점 공유 매분 30회·일일 3,000회 원장과 인증 세션을 보존하고, 예산이 부족하면 재시도 시각을 기다립니다.

수정 전의 잘못된 성공 응답이 Edge Cache에서 재사용되지 않도록 관련 조회 경로의 캐시 namespace도 갱신했습니다. 비교의 오래된 403 부분 결과를 캐시에 주입한 실제 앱 회귀 테스트로 새 조회가 수행되는 것을 확인했습니다.
6 changes: 3 additions & 3 deletions src/api/routes/cgvRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export function registerCgvRoutes(app: Hono<{ Bindings: AppBindings }>): void {
{
ttlSeconds: 60 * 60 * 24,
staleWhileRevalidateSeconds: 60 * 5,
keyPrefix: 'cgv-theaters-v2',
keyPrefix: 'cgv-theaters-v3',
},
() => handleCgvFindTheaters(c),
),
Expand All @@ -26,7 +26,7 @@ export function registerCgvRoutes(app: Hono<{ Bindings: AppBindings }>): void {
{
ttlSeconds: 60 * 10,
staleWhileRevalidateSeconds: 60,
keyPrefix: 'cgv-movies-v2',
keyPrefix: 'cgv-movies-v3',
},
() => handleCgvSearchMovies(c),
),
Expand All @@ -38,7 +38,7 @@ export function registerCgvRoutes(app: Hono<{ Bindings: AppBindings }>): void {
{
ttlSeconds: 60 * 3,
staleWhileRevalidateSeconds: 30,
keyPrefix: 'cgv-timetable-v2',
keyPrefix: 'cgv-timetable-v3',
},
() => handleCgvGetTimetable(c),
),
Expand Down
2 changes: 1 addition & 1 deletion src/api/routes/compareRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export function registerCompareRoutes(app: Hono<{ Bindings: AppBindings }>): voi
{
ttlSeconds: 60 * 10,
staleWhileRevalidateSeconds: 60,
keyPrefix: 'compare-products-v1',
keyPrefix: 'compare-products-v2',
},
() => handleCompareProducts(c),
),
Expand Down
4 changes: 2 additions & 2 deletions src/api/routes/cuRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export function registerCuRoutes(app: Hono<{ Bindings: AppBindings }>): void {
{
ttlSeconds: 60 * 60 * 24,
staleWhileRevalidateSeconds: 60 * 5,
keyPrefix: 'cu-stores-v3',
keyPrefix: 'cu-stores-v4',
},
() => handleCuFindStores(c),
),
Expand All @@ -26,7 +26,7 @@ export function registerCuRoutes(app: Hono<{ Bindings: AppBindings }>): void {
{
ttlSeconds: 60 * 10,
staleWhileRevalidateSeconds: 60,
keyPrefix: 'cu-inventory-v3',
keyPrefix: 'cu-inventory-v4',
},
() => handleCuCheckInventory(c),
),
Expand Down
10 changes: 5 additions & 5 deletions src/api/routes/daisoRoutes.ts
< 8000 /tr>
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export function registerDaisoRoutes(app: Hono<{ Bindings: AppBindings }>): void
{
ttlSeconds: 60 * 30,
staleWhileRevalidateSeconds: 60 * 3,
keyPrefix: 'daiso-products-v1',
keyPrefix: 'daiso-products-v2',
},
() => handleSearchProducts(c),
),
Expand All @@ -32,7 +32,7 @@ export function registerDaisoRoutes(app: Hono<{ Bindings: AppBindings }>): void
{
ttlSeconds: 60 * 60,
staleWhileRevalidateSeconds: 60 * 5,
keyPrefix: 'daiso-product-detail-v1',
keyPrefix: 'daiso-product-detail-v2',
},
() => handleGetProduct(c),
),
Expand All @@ -44,7 +44,7 @@ export function registerDaisoRoutes(app: Hono<{ Bindings: AppBindings }>): void
{
ttlSeconds: 60 * 60 * 24,
staleWhileRevalidateSeconds: 60 * 5,
keyPrefix: 'daiso-stores-v1',
keyPrefix: 'daiso-stores-v2',
},
() => handleFindStores(c),
),
Expand All @@ -56,7 +56,7 @@ export function registerDaisoRoutes(app: Hono<{ Bindings: AppBindings }>): void
{
ttlSeconds: 60 * 10,
staleWhileRevalidateSeconds: 60,
keyPrefix: 'daiso-inventory-v1',
keyPrefix: 'daiso-inventory-v2',
},
() => handleCheckInventory(c),
),
Expand All @@ -68,7 +68,7 @@ export function registerDaisoRoutes(app: Hono<{ Bindings: AppBindings }>): void
{
ttlSeconds: 60 * 10,
staleWhileRevalidateSeconds: 60,
keyPrefix: 'daiso-display-location-v1',
keyPrefix: 'daiso-display-location-v2',
},
() => handleGetDisplayLocation(c),
),
Expand Down
6 changes: 3 additions & 3 deletions src/api/routes/dtryxRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export function registerDtryxRoutes(app: Hono<{ Bindings: AppBindings }>): void
{
ttlSeconds: 60 * 60 * 24,
staleWhileRevalidateSeconds: 60 * 5,
keyPrefix: 'dtryx-cinemas-v1',
keyPrefix: 'dtryx-cinemas-v2',
},
() => handleDtryxListCinemas(c),
),
Expand All @@ -30,7 +30,7 @@ export function registerDtryxRoutes(app: Hono<{ Bindings: AppBindings }>): void
{
ttlSeconds: 60 * 10,
staleWhileRevalidateSeconds: 60,
keyPrefix: 'dtryx-movies-v1',
keyPrefix: 'dtryx-movies-v2',
},
() => handleDtryxListNowShowing(c),
),
Expand All @@ -42,7 +42,7 @@ export function registerDtryxRoutes(app: Hono<{ Bindings: AppBindings }>): void
{
ttlSeconds: 60 * 3,
staleWhileRevalidateSeconds: 30,
keyPrefix: 'dtryx-seats-v1',
keyPrefix: 'dtryx-seats-v2',
},
() => handleDtryxGetRemainingSeats(c),
),
Expand Down
6 changes: 3 additions & 3 deletions src/api/routes/emart24Routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export function registerEmart24Routes(app: Hono<{ Bindings: AppBindings }>): voi
{
ttlSeconds: 60 * 30,
staleWhileRevalidateSeconds: 60 * 3,
keyPrefix: 'emart24-stores-v1',
keyPrefix: 'emart24-stores-v2',
},
() => handleEmart24FindStores(c),
),
Expand All @@ -30,7 +30,7 @@ export function registerEmart24Routes(app: Hono<{ Bindings: AppBindings }>): voi
{
ttlSeconds: 60 * 10,
staleWhileRevalidateSeconds: 60,
keyPrefix: 'emart24-products-v1',
keyPrefix: 'emart24-products-v2',
},
() => handleEmart24SearchProducts(c),
),
Expand All @@ -42,7 +42,7 @@ export function registerEmart24Routes(app: Hono<{ Bindings: AppBindings }>): voi
{
ttlSeconds: 60 * 5,
staleWhileRevalidateSeconds: 60,
keyPrefix: 'emart24-inventory-v1',
keyPrefix: 'emart24-inventory-v2',
},
() => handleEmart24CheckInventory(c),
),
Expand Down
6 changes: 3 additions & 3 deletions src/api/routes/gs25Routes.ts
10BC8
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export function registerGs25Routes(app: Hono<{ Bindings: AppBindings }>): void {
{
ttlSeconds: 60 * 10,
staleWhileRevalidateSeconds: 60,
keyPrefix: 'gs25-stores-v2',
keyPrefix: 'gs25-stores-v3',
},
() => handleGs25FindStores(c),
),
Expand All @@ -30,7 +30,7 @@ export function registerGs25Routes(app: Hono<{ Bindings: AppBindings }>): void {
{
ttlSeconds: 60 * 3,
staleWhileRevalidateSeconds: 60,
keyPrefix: 'gs25-products-v2',
keyPrefix: 'gs25-products-v3',
},
() => handleGs25SearchProducts(c),
),
Expand All @@ -42,7 +42,7 @@ export function registerGs25Routes(app: Hono<{ Bindings: AppBindings }>): void {
{
ttlSeconds: 60 * 2,
staleWhileRevalidateSeconds: 30,
keyPrefix: 'gs25-inventory-v2',
keyPrefix: 'gs25-inventory-v3',
},
() => handleGs25CheckInventory(c),
),
Expand Down
6 changes: 3 additions & 3 deletions src/api/routes/lottecinemaRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export function registerLotteCinemaRoutes(app: Hono<{ Bindings: AppBindings }>):
{
ttlSeconds: 60 * 60 * 24,
staleWhileRevalidateSeconds: 60 * 5,
keyPrefix: 'lottecinema-theaters-v2',
keyPrefix: 'lottecinema-theaters-v3',
},
() => handleLotteCinemaFindNearbyTheaters(c),
),
Expand All @@ -30,7 +30,7 @@ export function registerLotteCinemaRoutes(app: Hono<{ Bindings: AppBindings }>):
{
ttlSeconds: 60 * 10,
staleWhileRevalidateSeconds: 60,
keyPrefix: 'lottecinema-movies-v2',
keyPrefix: 'lottecinema-movies-v3',
},
() => handleLotteCinemaListNowShowing(c),
),
Expand All @@ -42,7 +42,7 @@ export function registerLotteCinemaRoutes(app: Hono<{ Bindings: AppBindings }>):
{
ttlSeconds: 60 * 3,
staleWhileRevalidateSeconds: 30,
keyPrefix: 'lottecinema-seats-v2',
keyPrefix: 'lottecinema-seats-v3',
},
() => handleLotteCinemaGetRemainingSeats(c),
),
Expand Down
6 changes: 3 additions & 3 deletions src/api/routes/megaboxRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export function registerMegaboxRoutes(app: Hono<{ Bindings: AppBindings }>): voi
{
ttlSeconds: 60 * 60 * 24,
staleWhileRevalidateSeconds: 60 * 5,
keyPrefix: 'megabox-theaters-v2',
keyPrefix: 'megabox-theaters-v3',
},
() => handleMegaboxFindNearbyTheaters(c),
),
Expand All @@ -30,7 +30,7 @@ export function registerMegaboxRoutes(app: Hono<{ Bindings: AppBindings }>): voi
{
ttlSeconds: 60 * 10,
staleWhileRevalidateSeconds: 60,
keyPrefix: 'megabox-movies-v2',
keyPrefix: 'megabox-movies-v3',
},
() => handleMegaboxListNowShowing(c),
),
Expand All @@ -42,7 +42,7 @@ export function registerMegaboxRoutes(app: Hono<{ Bindings: AppBindings }>): voi
{
ttlSeconds: 60 * 3,
staleWhileRevalidateSeconds: 30,
keyPrefix: 'megabox-seats-v2',
keyPrefix: 'megabox-seats-v3',
},
() => handleMegaboxGetRemainingSeats(c),
),
Expand Down
6 changes: 3 additions & 3 deletions src/api/routes/oliveyoungRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export function registerOliveyoungRoutes(app: Hono<{ Bindings: AppBindings }>):
{
ttlSeconds: 60 * 5,
staleWhileRevalidateSeconds: 60,
keyPrefix: 'oliveyoung-products-v2',
keyPrefix: 'oliveyoung-products-v3',
},
() => handleOliveyoungSearchProducts(c),
),
Expand All @@ -31,7 +31,7 @@ export function registerOliveyoungRoutes(app: Hono<{ Bindings: AppBindings }>):
{
ttlSeconds: 60 * 60 * 24,
staleWhileRevalidateSeconds: 60 * 5,
keyPrefix: 'oliveyoung-stores-v2',
keyPrefix: 'oliveyoung-stores-v3',
},
() => handleOliveyoungFindStores(c),
),
Expand All @@ -43,7 +43,7 @@ export function registerOliveyoungRoutes(app: Hono<{ Bindings: AppBindings }>):
{
ttlSeconds: 60 * 10,
staleWhileRevalidateSeconds: 60,
keyPrefix: 'oliveyoung-inventory-v2',
keyPrefix: 'oliveyoung-inventory-v3',
},
() => handleOliveyoungCheckInventory(c),
),
Expand Down
8 changes: 4 additions & 4 deletions src/api/routes/opinetRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export function registerOpinetRoutes(app: Hono<{ Bindings: AppBindings }>): void
{
ttlSeconds: 60 * 60,
staleWhileRevalidateSeconds: 60 * 30,
keyPrefix: 'opinet-average-v2',
keyPrefix: 'opinet-average-v3',
},
() => handleOpinetAveragePrices(c),
),
Expand All @@ -27,7 +27,7 @@ export function registerOpinetRoutes(app: Hono<{ Bindings: AppBindings }>): void
{
ttlSeconds: 60 * 30,
staleWhileRevalidateSeconds: 60 * 10,
keyPrefix: 'opinet-lowest-v2',
keyPrefix: 'opinet-lowest-v3',
},
() => handleOpinetLowestStations(c),
),
Expand All @@ -39,7 +39,7 @@ export function registerOpinetRoutes(app: Hono<{ Bindings: AppBindings }>): void
{
ttlSeconds: 60 * 20,
staleWhileRevalidateSeconds: 60 * 5,
keyPrefix: 'opinet-around-v2',
keyPrefix: 'opinet-around-v3',
},
() => handleOpinetStationsAround(c),
),
Expand All @@ -51,7 +51,7 @@ export function registerOpinetRoutes(app: Hono<{ Bindings: AppBindings }>): void
{
ttlSeconds: 60 * 60,
staleWhileRevalidateSeconds: 60 * 10,
keyPrefix: 'opinet-station-v2',
keyPrefix: 'opinet-station-v3',
},
() => handleOpinetStationDetail(c),
),
Expand Down
2 changes: 1 addition & 1 deletion src/api/routes/placesRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export function registerPlacesRoutes(app: Hono<{ Bindings: AppBindings }>): void
{
ttlSeconds: 60 * 60,
staleWhileRevalidateSeconds: 60 * 10,
keyPrefix: 'places-search-v1',
keyPrefix: 'places-search-v2',
},
() => handlePlacesSearch(c),
),
Expand Down
10 changes: 5 additions & 5 deletions src/api/routes/sevenelevenRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export function registerSevenElevenRoutes(app: Hono<{ Bindings: AppBindings }>):
{
ttlSeconds: 60 * 3,
staleWhileRevalidateSeconds: 60,
keyPrefix: 'seveneleven-products-v1',
keyPrefix: 'seveneleven-products-v2',
},
() => handleSevenElevenSearchProducts(c),
),
Expand All @@ -32,7 +32,7 @@ export function registerSevenElevenRoutes(app: Hono<{ Bindings: AppBindings }>):
{
ttlSeconds: 60 * 3,
staleWhileRevalidateSeconds: 60,
keyPrefix: 'seveneleven-stores-v1',
keyPrefix: 'seveneleven-stores-v2',
},
() => handleSevenElevenSearchStores(c),
),
Expand All @@ -44,7 +44,7 @@ export function registerSevenElevenRoutes(app: Hono<{ Bindings: AppBindings }>):
{
ttlSeconds: 60 * 10,
staleWhileRevalidateSeconds: 60,
keyPrefix: 'seveneleven-inventory-v1',
keyPrefix: 'seveneleven-inventory-v2',
},
() => handleSevenElevenCheckInventory(c),
),
Expand All @@ -56,7 +56,7 @@ export function registerSevenElevenRoutes(app: Hono<{ Bindings: AppBindings }>):
{
ttlSeconds: 60 * 5,
staleWhileRevalidateSeconds: 60,
keyPrefix: 'seveneleven-popwords-v1',
keyPrefix: 'seveneleven-popwords-v2',
},
() => handleSevenElevenGetSearchPopwords(c),
),
Expand All @@ -68,7 +68,7 @@ export function registerSevenElevenRoutes(app: Hono<{ Bindings: AppBindings }>):
{
ttlSeconds: 60 * 5,
staleWhileRevalidateSeconds: 60,
keyPrefix: 'seveneleven-catalog-v1',
keyPrefix: 'seveneleven-catalog-v2',
},
() => handleSevenElevenGetCatalogSnapshot(c),
),
Expand Down
2 changes: 1 addition & 1 deletion tests/api/cu-relay-keyword.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ it.each([
expect(text).toContain('강남예시점');
expect(text).not.toContain('시청예시점');
const newKey = new URL(url);
newKey.searchParams.append('__cache_prefix', `${prefix}-v3`);
newKey.searchParams.append('__cache_prefix', `${prefix}-v4`);
expect(match.mock.calls[0][0].url).toBe(newKey.href);
expect(put.mock.calls[0][0].url).toBe(newKey.href);
expect(response.headers.get('Cache-Control')).toContain(`max-age=${ttl}`);
Expand Down
18 changes: 18 additions & 0 deletions tests/app/quality-cache-migration.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { afterEach, expect, it, vi } from 'vitest';
import app from '../../src/index.js';

afterEach(() => vi.unstubAllGlobals());
it('개선 전 비교 캐시의 실패 결과 대신 수정된 조회를 반환한다', async () => {
const old = Response.json({ success: true, data: { results: [], errors: [{ service: 'gs25', message: 'old 403' }] } });
const put = vi.fn();
vi.stubGlobal('caches', { default: {
match: async (request: Request) => new URL(request.url).searchParams.get('__cache_prefix') === 'compare-products-v1' ? old.clone() : undefined,
put,
} });
const fetcher = vi.fn(async () => Response.json({ resultSet: { result: [{ totalSize: 1, resultDocuments: [{ PD_NO: 'P', PDNM: '현재 상품', PD_PRC: '1000' }] }] } }));
vi.stubGlobal('fetch', fetcher);
const response = await app.request('/api/compare/products?keyword=콜라&services=daiso&limit=1');
expect(await response.json()).toMatchObject({ data: { results: [{ code: 'P', name: '현재 상품' }], errors: [] } });
expect(fetcher).toHaveBeenCalledTimes(1);
expect(put).toHaveBeenCalledTimes(1);
});
Loading
0