[25.12.23 / TASK-261] Feature - 직접 새로고침 API (프로듀서) 추가#48
Conversation
Walkthrough통계 강제 갱신(refresh) 흐름이 추가되었습니다. 컨트롤러·라우터·서비스·저장소에 refresh 경로와 로직이 도입되고, Redis 기반 큐(push/isUserInQueue) 및 최신 갱신 시각 조회, 응답 DTO와 관련 단위 테스트들이 추가되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Client
participant Controller as TotalStatsController
participant Service as TotalStatsService
participant Repo as TotalStatsRepository
participant Cache as RedisCache
participant Redis
Client->>Controller: POST /stats-refresh (auth, userId)
Controller->>Service: refreshStats(userId)
Service->>Repo: getLatestUpdatedAt(userId)
Repo-->>Service: lastUpdatedAt (string|null)
alt lastUpdatedAt within 15 minutes
Service-->>Controller: {success:false, reason:'up-to-date', lastUpdatedAt}
Controller-->>Client: HTTP 409 + payload
else
Service->>Cache: isUserInQueue(PROCESSING_QUEUE_KEY, userId)
Cache->>Redis: LRANGE processingKey 0 -1
Redis-->>Cache: list items
Cache-->>Service: boolean (inQueue)
alt inQueue == true
Service-->>Controller: {success:false, reason:'in-progress'}
Controller-->>Client: HTTP 409 + payload
else
Service->>Cache: pushToQueue(MAIN_QUEUE_KEY, jobData)
Cache->>Redis: LPUSH mainKey serialized(jobData)
Redis-->>Cache: new length
Cache-->>Service: number|null
alt push succeeded
Service-->>Controller: {success:true}
Controller-->>Client: HTTP 202 + payload
else
Service-->>Controller: throws
Controller-->>Client: HTTP 500 + payload
end
end
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
src/modules/cache/redis.cache.ts (1)
276-276: 키 접두사 일관성 문제 (pushToQueue와 동일)
isUserInQueue도 하드코딩된vd2:queue:접두사를 사용합니다.pushToQueue와 함께 설정 가능한 접두사 패턴으로 변경하는 것이 좋습니다.
🧹 Nitpick comments (4)
src/services/totalStats.service.ts (1)
57-69: 큐 등록 로직이 적절합니다.큐 실패 시 명확한 에러를 throw하고 있습니다.
디버깅을 위해 성공 시에도 큐 길이를 로깅하는 것을 고려해보세요:
선택적 개선사항
const queueLength = await redisCache.pushToQueue(this.MAIN_QUEUE_KEY, { userId: userId, requestedAt: new Date().toISOString(), retryCount: 0, }); if (queueLength === null) { logger.error('Failed to add job to Redis Queue'); throw new Error('통계 새로고침 작업 등록에 실패했습니다.'); } +logger.info(`Stats refresh job queued for user ${userId}, queue length: ${queueLength}`); return { success: true };src/modules/cache/redis.cache.ts (2)
245-261: 키 접두사 일관성 문제: 하드코딩된 접두사 사용
pushToQueue메서드가 하드코딩된vd2:queue:접두사를 사용하고 있습니다. 다른 캐시 메서드들은 설정 가능한this.keyPrefix를 사용하는 패턴을 따르고 있어 일관성이 떨어집니다. 큐 전용 접두사가 필요하다면 생성자에서 설정 가능하도록 하거나, 최소한getFullKey패턴을 따르도록 개선하는 것이 좋습니다.🔎 설정 가능한 큐 접두사를 위한 제안
생성자에 queuePrefix 추가:
constructor(config: CacheConfig) { this.keyPrefix = config.keyPrefix || 'vd2:cache:'; + this.queuePrefix = config.queuePrefix || 'vd2:queue:'; this.defaultTTL = config.defaultTTL || 300;그리고 메서드에서 사용:
async pushToQueue<T>(queueKey: string, data: T): Promise<number | null> { try { if (!this.connected) { logger.warn('Redis not connected, skipping queue push'); return null; } - const fullKey = `vd2:queue:${queueKey}`; + const fullKey = `${this.queuePrefix}${queueKey}`; const serializedData = JSON.stringify(data); const length = await this.client.lPush(fullKey, serializedData); return length; } catch (error) { logger.error(`Queue PUSH error for key ${queueKey}:`, error); return null; } }
269-298: 큐 조회의 O(n) 성능 특성 고려
isUserInQueue메서드가LRANGE 0 -1을 사용하여 전체 큐를 스캔하므로 큐 크기에 따라 O(n) 성능 특성을 가집니다. 현재 코드는 단 하나의 위치(getTotalStats의 중복 처리 방지)에서만 호출되며, 통계 갱신 요청이라는 제한된 사용 사례이므로 실질적인 성능 문제는 미미할 것으로 예상됩니다.그러나 향후 큐 사용이 확장될 경우를 대비하여, 다음과 같은 개선을 고려할 수 있습니다:
- Redis Set을 병행하여 O(1) 조회 구현 (예:
vd2:queue:users:${queueKey})- 큐 처리 워커의 추가 및 명확한 생명주기 관리
- 불필요한 데이터는 TTL 설정으로 자동 정리
현재 구현이 요구사항을 충족한다면 그대로 유지하되, 큐 규모가 커질 경우 이를 재검토하는 것이 권장됩니다.
src/controllers/totalStats.controller.ts (1)
30-62: 제어 흐름 개선 제안
refreshStats메서드의 로직이 전반적으로 정확하지만, 다음과 같은 개선사항을 고려할 수 있습니다:
Line 41:
as string타입 단언은result.lastUpdatedAt의 타입이 보장되지 않음을 시사합니다. 서비스 레이어의 반환 타입을 명확히 정의하면 타입 안전성이 향상됩니다.Lines 37-50: 각 조건 블록 내에서 응답을 보낸 후 명시적으로
return하는 것이 제어 흐름을 더 명확하게 만듭니다. 현재는 line 52의return에 의존하고 있습니다.Exhaustiveness:
result.success가 false이지만reason이 'up-to-date'나 'in-progress'가 아닌 경우에 대한 처리가 없습니다. 예상치 못한 상태에 대한 기본 처리나 로깅을 추가하는 것이 좋습니다.🔎 제어 흐름 개선 예시
refreshStats: RequestHandler = async (req: Request, res: Response<StatsRefreshResponseDto>, next: NextFunction) => { try { const { id } = req.user; const result = await this.totalStatsService.refreshStats(id); if (!result.success) { if (result.reason === 'up-to-date') { const response = new StatsRefreshResponseDto( false, '통계가 최신 상태입니다.', { lastUpdatedAt: result.lastUpdatedAt as string }, null, ); - res.status(409).json(response); + return res.status(409).json(response); } if (result.reason === 'in-progress') { const response = new StatsRefreshResponseDto(false, '이미 통계 새로고침이 진행 중입니다.', {}, null); - res.status(409).json(response); + return res.status(409).json(response); } - return; + // 예상치 못한 실패 케이스 처리 + logger.warn(`Unexpected refresh result: ${JSON.stringify(result)}`); + const response = new StatsRefreshResponseDto(false, '통계 새로고침 요청을 처리할 수 없습니다.', {}, null); + return res.status(500).json(response); } const response = new StatsRefreshResponseDto(true, '통계 새로고침 요청이 성공적으로 등록되었습니다.', {}, null); - res.status(202).json(response); + return res.status(202).json(response); } catch (error) { logger.error('통계 새로고침 실패:', error); next(error); } };
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
src/controllers/totalStats.controller.tssrc/modules/cache/__test__/redis.cache.test.tssrc/modules/cache/redis.cache.tssrc/repositories/__test__/totalStats.repo.test.tssrc/repositories/totalStats.repository.tssrc/routes/totalStats.router.tssrc/services/__test__/totalStats.service.test.tssrc/services/totalStats.service.tssrc/types/dto/responses/totalStatsResponse.type.tssrc/types/index.ts
🧰 Additional context used
🧬 Code graph analysis (5)
src/repositories/totalStats.repository.ts (1)
src/exception/index.ts (1)
DBError(2-2)
src/types/dto/responses/totalStatsResponse.type.ts (2)
src/types/index.ts (3)
TotalStatsResponseDto(39-39)TotalStatsItem(37-37)StatsRefreshResponseDto(40-40)src/types/dto/responses/baseResponse.type.ts (1)
BaseResponseDto(28-40)
src/services/totalStats.service.ts (1)
src/configs/cache.config.ts (1)
cache(17-17)
src/routes/totalStats.router.ts (1)
src/middlewares/auth.middleware.ts (1)
authMiddleware(110-113)
src/controllers/totalStats.controller.ts (2)
src/types/dto/responses/totalStatsResponse.type.ts (1)
StatsRefreshResponseDto(66-66)src/types/index.ts (1)
StatsRefreshResponseDto(40-40)
🔇 Additional comments (13)
src/types/index.ts (1)
40-40: LGTM!새로운 DTO 타입을 일관된 패턴으로 export하고 있습니다.
src/routes/totalStats.router.ts (2)
73-119: LGTM!새로고침 엔드포인트에 대한 Swagger 문서가 잘 작성되어 있습니다. 다양한 응답 시나리오(최신 상태, 진행 중)에 대한 예시가 명확하게 제공되어 있습니다.
120-120: LGTM!라우트가 인증 미들웨어로 보호되고 있으며, 요청 본문이 없으므로 별도의 유효성 검사 미들웨어가 필요하지 않습니다.
src/types/dto/responses/totalStatsResponse.type.ts (1)
44-66: LGTM!
StatsRefreshResponseDto가 적절하게 정의되어 있습니다.lastUpdatedAt필드가 선택적으로 설계되어 다양한 응답 시나리오(최신 상태 vs 대기열 등록)를 잘 지원합니다.src/repositories/__test__/totalStats.repo.test.ts (1)
226-256: LGTM!
getLatestUpdatedAt메서드에 대한 테스트 커버리지가 적절합니다. 성공 케이스, null 반환, 에러 처리 시나리오를 모두 검증하고 있습니다.src/modules/cache/__test__/redis.cache.test.ts (2)
545-601: LGTM!
pushToQueue메서드의 테스트가 포괄적입니다. JSON 직렬화, 에러 처리, 연결 상태 확인 등 주요 시나리오를 잘 검증하고 있습니다.
603-694: LGTM!
isUserInQueue메서드의 테스트가 매우 철저합니다. 특히 잘못된 JSON 항목이 있어도 검색을 계속하는 복원력 테스트(Lines 661-671)가 훌륭합니다.src/services/__test__/totalStats.service.test.ts (1)
1-135: LGTM!
refreshStats메서드에 대한 테스트 커버리지가 훌륭합니다. 가짜 타이머를 사용하여 시간 기반 로직을 정확하게 테스트하고 있으며, 성공/실패/엣지 케이스를 모두 검증합니다.src/services/totalStats.service.ts (3)
8-10: LGTM!새로고침 간격과 큐 키 상수가 명확하게 정의되어 있습니다. 15분 간격은 Swagger 문서의 설명과 일치합니다.
36-47: LGTM!시간 비교 로직이 정확합니다. 15분 이내의 업데이트는 최신 상태로 처리하고, null 케이스(이전 업데이트 없음)도 적절히 처리합니다.
70-74: LGTM!에러 처리가 일관되게 구현되어 있습니다. 에러를 로깅한 후 상위 레이어로 전파하는 패턴이 기존
getTotalStats메서드와 동일합니다.src/controllers/totalStats.controller.ts (2)
3-3: LGTM: 새로운 응답 DTO 임포트
StatsRefreshResponseDto임포트가 적절하게 추가되었습니다.
55-57: 적절한 HTTP 상태 코드 사용비동기 처리를 위한 202 Accepted 상태 코드 사용이 적절합니다. 큐에 작업이 등록되었고 나중에 처리될 것임을 올바르게 나타냅니다.
| if (!result.success) { | ||
| if (result.reason === 'up-to-date') { | ||
| const response = new StatsRefreshResponseDto( | ||
| false, | ||
| '통계가 최신 상태입니다.', | ||
| { lastUpdatedAt: result.lastUpdatedAt as string }, | ||
| null, | ||
| ); | ||
| res.status(409).json(response); | ||
| } | ||
|
|
||
| if (result.reason === 'in-progress') { | ||
| const response = new StatsRefreshResponseDto(false, '이미 통계 새로고침이 진행 중입니다.', {}, null); | ||
| res.status(409).json(response); | ||
| } | ||
|
|
||
| return; | ||
| } | ||
|
|
||
| const response = new StatsRefreshResponseDto(true, '통계 새로고침 요청이 성공적으로 등록되었습니다.', {}, null); | ||
|
|
||
| res.status(202).json(response); |
There was a problem hiding this comment.
- 이럴땐 차라리
result.success가true일때를 처리하는게 나을 것 같아요. reason이 2가지 말고 다른 이유일 가능성이 없나요?
There was a problem hiding this comment.
에러 필터에 걸리지 않게끔 처리하는 케이스에 대해선 이 2가지만 있는 것 같습니다!
| const fullKey = `vd2:queue:${queueKey}`; | ||
|
|
||
| // LRANGE로 큐의 모든 항목 조회 | ||
| const items = await this.client.lRange(fullKey, 0, -1); |
There was a problem hiding this comment.
이게 무조건 O(n) 이 될 수 밖에 없는데,
pushToQueue 에 되는 것을 "특정 유저 값" 과 같은 유니크 값으로 "다른 큐에" 에 Add를 같이 한다면, sIsMember 로 O(1) 체크할 수 있어요.
그 대신 그 만큼의 메모리를 더 쓰겠지만, 이는 trade-off 에 대해 고민해 볼 법 한 것 같아요.
There was a problem hiding this comment.
너무 좋은 아이디어 감사합니다! 😊
실제 구현도 해보고 고민해봤는데 현재로썬 Queue 크기가 그렇게 클 것 같지도 않고, 백오피스에서도 대응 개발해야하는 부분이나 API 서버 코드에서도 복잡도가 좀 올라가는 것 같아서 해당하는 부분은 나중에 병목 생기면 리팩토링 하는 방향으로 가고 싶습니다. 괜찮을까요?
Nuung
left a comment
There was a problem hiding this comment.
좋았던 점
- redis 에 대한 처리를 같이 하다보면 생각보다 QA와 커버할게 넓어져서 쉽지 않았을텐데, 너무 잘 마무리해주신 것 같아요! 고생 많으셨습니다!
- 기존 redis 구현체 재활용과 테스트 코드까지 짱이었어요 ㅎㄷㄷ
아쉬운 점
- redis를 사용할때 고민할 디테일들이 조금 아쉬웠습니다. 코멘트 확인해 주세요!
- 그 외 디테일한 부분이었고, 전체적으로 크게 아쉬운게 없어요!! 너무 고생많으셨어요!
There was a problem hiding this comment.
코드 잘 봤습니다! 전반적으로 비동기 작업 처리 구조가 노션에 기재해주셨던 방향대로 탄탄하게 설계해주신 것 같고, 테스트도 꼼꼼히 구현해주신 점이 좋았습니다:)
좋았던 점
- pushToQueue와 isUserInQueue 메서드를 테스트 코드로 꼼꼼하게 검증하신 부분이 인상적이었습니다. 특히 잘못된 JSON 파싱 케이스까지 고려하신 부분이 좋았습니다👍
- 15분 간격 제한을 상수로 관리하고, 큐 키도 클래스 속성으로 관리해 매직 넘버 및 스트링을 제거하신 점이 좋았습니다!
six-standard
left a comment
There was a problem hiding this comment.
코드 잘 읽었습니다!
현우님이랑 의견 동일해서, 저 부분들만 처리해주시면 될 듯 합니다..!
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (1)
src/modules/cache/redis.cache.ts (1)
286-286: 엄격한 동등 비교(===)를 사용해야 합니다.느슨한 동등 비교(
==)는 타입 강제 변환을 허용하여 예상치 못한 동작을 유발할 수 있습니다. 예를 들어,parsedItem.userId가 문자열"123"이고userId가 숫자123일 경우==는true를 반환하지만, 이는 타입 불일치를 숨길 수 있습니다.🔎 수정 제안
- if (parsedItem.userId == userId) { + if (parsedItem.userId === userId) { return true; }
🧹 Nitpick comments (1)
src/controllers/totalStats.controller.ts (1)
36-54: 응답 분기 로직을 더 명시적으로 개선할 수 있습니다.현재 로직은
reason이 'up-to-date'나 'in-progress'가 아닐 경우 암묵적으로 성공으로 처리합니다.result.success속성을 명시적으로 확인하여 예상치 못한 응답 구조에 대한 견고성을 높이는 것을 권장합니다.🔎 제안하는 개선 방안
const result = await this.totalStatsService.refreshStats(id); +if (result.success) { + const response = new StatsRefreshResponseDto(true, '통계 새로고침 요청이 성공적으로 등록되었습니다.', {}, null); + res.status(202).json(response); + return; +} + if (result.reason === 'up-to-date') { const response = new StatsRefreshResponseDto( false, '통계가 최신 상태입니다.', { lastUpdatedAt: result.lastUpdatedAt }, null, ); res.status(409).json(response); return; } if (result.reason === 'in-progress') { const response = new StatsRefreshResponseDto(false, '이미 통계 새로고침이 진행 중입니다.', {}, null); res.status(409).json(response); return; } -const response = new StatsRefreshResponseDto(true, '통계 새로고침 요청이 성공적으로 등록되었습니다.', {}, null); -res.status(202).json(response); +// 예상치 못한 응답 구조 처리 +throw new Error('Unexpected refresh result structure');
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
src/configs/cache.config.tssrc/controllers/totalStats.controller.tssrc/modules/cache/__test__/redis.cache.test.tssrc/modules/cache/redis.cache.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- src/modules/cache/test/redis.cache.test.ts
🧰 Additional context used
🧬 Code graph analysis (1)
src/controllers/totalStats.controller.ts (2)
src/types/dto/responses/totalStatsResponse.type.ts (1)
StatsRefreshResponseDto(66-66)src/types/index.ts (1)
StatsRefreshResponseDto(40-40)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: build-and-test (20)
- GitHub Check: build-and-test (23)
- GitHub Check: build-and-test (22)
- GitHub Check: build-and-test (21)
🔇 Additional comments (3)
src/configs/cache.config.ts (1)
11-11: 키 prefix 변경이 올바르게 적용되었습니다.기존
'vd2:cache:'에서'vd2:'로 변경하여getFullKey에서 타입별로 prefix를 추가하는 새로운 구조와 일치합니다. 이 변경으로 캐시와 큐가 명확히 구분됩니다.src/modules/cache/redis.cache.ts (2)
13-13: 키 prefix 리팩토링이 잘 적용되었습니다.
getFullKey를 범용적으로 사용하도록 개선하여 캐시와 큐를 명확히 구분할 수 있게 되었습니다. 타입 파라미터를 통해 타입 안정성도 확보되었습니다.Also applies to: 58-60
246-262: 큐 추가 메서드가 올바르게 구현되었습니다.
pushToQueue메서드는 Redis List를 활용하여 큐 기능을 제공하며, 에러 처리와 연결 상태 확인도 적절히 수행합니다.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
.env.sample (1)
24-29: 선택사항: Redis 환경 변수 정렬 순서 개선dotenv-linter 분석 결과,
REDIS_KEY_PREFIX(29줄)이REDIS_PASSWORD(27줄) 이후에 위치하고 있습니다. 일반적인 env 파일 관례에 따라 관련 설정들을 그룹화하고 알파벳 순서로 정렬하면 가독성이 개선될 수 있습니다. 프로젝트의 스타일 가이드에 따라 정렬 순서를 일관되게 유지할 것을 권장합니다.🔎 제안된 정렬 순서 조정
# Cache (redis) REDIS_HOST=localhost -REDIS_PORT=6379 -REDIS_PASSWORD=notion-check-plz -REDIS_DB=0 REDIS_KEY_PREFIX=vd2: +REDIS_PASSWORD=notion-check-plz +REDIS_PORT=6379 +REDIS_DB=0 CACHE_DEFAULT_TTL=300
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
.env.sample
🧰 Additional context used
🪛 dotenv-linter (4.0.0)
.env.sample
[warning] 29-29: [UnorderedKey] The REDIS_KEY_PREFIX key should go before the REDIS_PASSWORD key
(UnorderedKey)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: build-and-test (22)
- GitHub Check: build-and-test (20)
- GitHub Check: build-and-test (23)
- GitHub Check: build-and-test (21)
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
src/services/totalStats.service.ts (1)
102-103: 타입 단언 관련 의도 주석 추가 권장이전 리뷰에서 논의된 대로,
ICache는 범용 인터페이스로 유지하고 Redis 전용 메서드는 타입 단언으로 사용하는 설계 결정이 확인되었습니다. 코드의 의도를 명확히 하기 위해 주석을 추가하는 것을 권장합니다.🔎 주석 추가 제안
// 3. Processing Queue에 userId 존재 확인 + // Redis 전용 큐 메서드 사용을 위한 타입 단언 (ICache는 범용 인터페이스로 유지) const redisCache = cache as RedisCache;
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
src/controllers/totalStats.controller.tssrc/repositories/totalStats.repository.tssrc/routes/totalStats.router.tssrc/services/totalStats.service.tssrc/types/dto/responses/totalStatsResponse.type.tssrc/types/index.ts
🚧 Files skipped from review as they are similar to previous changes (4)
- src/routes/totalStats.router.ts
- src/types/index.ts
- src/repositories/totalStats.repository.ts
- src/controllers/totalStats.controller.ts
🧰 Additional context used
🧬 Code graph analysis (2)
src/types/dto/responses/totalStatsResponse.type.ts (2)
src/types/index.ts (1)
StatsRefreshResponseDto(47-47)src/types/dto/responses/baseResponse.type.ts (1)
BaseResponseDto(28-40)
src/services/totalStats.service.ts (2)
src/configs/cache.config.ts (1)
cache(17-17)src/modules/cache/redis.cache.ts (1)
RedisCache(6-300)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: build-and-test (23)
- GitHub Check: build-and-test (20)
- GitHub Check: build-and-test (21)
- GitHub Check: build-and-test (22)
🔇 Additional comments (5)
src/types/dto/responses/totalStatsResponse.type.ts (1)
185-205: 잘 구현되었습니다!새로운
StatsRefreshResponseDto가 기존 파일의 패턴을 잘 따르고 있으며, 타입 정의와 Swagger 문서화가 일관성 있게 작성되었습니다.lastUpdatedAt을 선택적 필드로 정의한 것은 409(이미 최신 상태)와 202(큐에 추가됨) 응답을 모두 유연하게 처리할 수 있어 적절합니다.src/services/totalStats.service.ts (4)
5-6: LGTM!캐시 관련 import가 적절하게 추가되었습니다.
16-18: LGTM!상수 정의가 명확하고, 큐 키 네이밍 컨벤션이 일관성 있게 유지되었습니다.
84-126: 전체적인 refreshStats 로직 승인새로고침 API의 프로듀서 역할이 명확하게 구현되었습니다:
- 15분 간격 체크로 불필요한 새로고침 방지
- 진행 중인 작업 중복 방지
- 적절한 에러 핸들링 및 로깅
- 반환 타입이 명확하여 컨트롤러에서 분기 처리 용이
위에서 언급한 메인 큐 중복 등록 가능성만 확인해 주시면 됩니다.
92-98: 타임존 처리 관련 타입 주석 검증 필요리포지토리 메서드가
Promise<string | null>로 선언되어 있으나, pg 라이브러리의 기본 동작(v8.13.1)은 PostgreSQL TIMESTAMP 컬럼을 Date 객체로 변환합니다. 현재 코드의new Date(latestUpdatedAt)는 문자열과 Date 객체 모두에서 동작하지만, 타입 선언과 실제 동작이 일치하는지 확인이 필요합니다.테스트에서는
'2025-05-30T12:00:00.000Z'형식의 ISO 8601 문자열(Z 타임존 포함)로 모킹하고 있으므로, 실제 데이터베이스 반환값도 타임존 정보를 포함하는지 검증하세요.
🔥 변경 사항
직접 새로고침의 프로듀서 역할을 하는 API를 추가하였습니다.
최신 업데이트가 되어있는 경우엔lastUpdatedAt을 내려보내야 해서, 에러를 던지는 대신 컨트롤러에서 분기하여 처리하도록 했습니다.이미 진행중인 경우도 에러를 던지는 대신 정상적으로 응답하도록 했습니다.즐거운 성탄절 보내세요!! 🎄🧑🏻🎄
🏷 관련 이슈
📸 스크린샷 (UI 변경 시 필수)
X
📌 체크리스트
Summary by CodeRabbit
새 기능
수정/설정
테스트
✏️ Tip: You can customize this high-level summary in your review settings.