-
Notifications
You must be signed in to change notification settings - Fork 0
Feature / EventLog #138
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Feature / EventLog #138
Conversation
Walkthrough이 변경은 페이지 뷰 이벤트 수집 기능을 추가합니다. 클라이언트용 POST 엔드포인트(EventLogController)와 요청 DTO/PageViewCommand, DeviceType/EventType/IdentityType 등 도메인 타입, Redis 기반 버퍼와 DLQ를 제공하는 EventLogStore, 이벤트 직렬화 및 푸시를 담당하는 EventLogIngestService, 주기적(10분) 또는 수동으로 Redis에서 배치로 읽어 DB에 저장하는 EventLogFlushScheduler, JPA 엔티티(EventLogEntity)와 리포지토리, 관련 단위 테스트들이 추가되었으며 build.gradle에 jackson-datatype-jsr310 의존성이 추가되었습니다. Sequence Diagram(s)sequenceDiagram
actor Client
participant Controller as EventLogController
participant Service as EventLogIngestService
participant Store as EventLogStore (Redis)
participant Scheduler as EventLogFlushScheduler
participant Repo as EventLogRepository
participant DB as Database
Client->>Controller: POST /api/v1/event-logs/page-view (deviceType, headers)
Controller->>Controller: 생성 PageViewCommand(eventId, appId, deviceType, ip, occurredAt)
Controller->>Service: ingestPageView(PageViewCommand)
Service->>Service: 직렬화(JSON)
Service->>Store: pushPageView(appId, json)
Store->>Store: set 등록(appId) 및 list rightPush(json) + TTL
Controller-->>Client: 202 Accepted
Note over Scheduler: 매 10분마다 또는 수동 호출
Scheduler->>Store: getRegisteredApps()
Store-->>Scheduler: [appId...]
loop 앱별
Scheduler->>Store: lrange bufferKey(appId) (최대 2000)
Store-->>Scheduler: [json...]
Scheduler->>Scheduler: parse -> EventLogEntity 리스트
Scheduler->>Repo: saveAll(entities)
alt saveAll 성공
Repo->>DB: 대량 INSERT
else saveAll 실패
Scheduler->>Repo: save(entity) 하나씩
alt 개별 저장 실패
Scheduler->>Store: pushDeadLetter(appId, rawJson, reason)
end
end
Scheduler->>Store: trim(처리된개수)
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧹 Recent nitpick comments
📜 Recent review detailsConfiguration used: Organization UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (1)
✏️ Tip: You can disable this entire section by setting 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
🤖 Fix all issues with AI agents
In `@src/main/java/redot/redot_server/domain/eventlog/service/EventLogStore.java`:
- Around line 40-44: getRegisteredApps currently maps Redis string members to
Long using Long::valueOf without handling NumberFormatException; wrap parsing in
defensive logic inside getRegisteredApps (using
stringRedisTemplate.opsForSet().members(APPS_KEY)) to skip or filter out
non-numeric values by attempting Long.parseLong/Long.valueOf in a try/catch per
item, log a warning including the offending value when parsing fails, and return
only successfully parsed Longs (empty list if none).
- Around line 21-22: APPS_KEY currently accumulates app IDs indefinitely because
there is no TTL or cleanup; modify EventLogStore to remove apps when their
buffers are empty by calling unregisterApp() after a successful flush (in
flushApp()), or alternatively set a TTL on APPS_KEY when adding entries, or add
a periodic cleanup task that scans APPS_KEY and unregisters apps whose buffer
keys are empty; update the flushApp() flow to check the buffer size/result and
call unregisterApp(appId) when empty (or implement a scheduled cleaner method in
EventLogStore that iterates APPS_KEY and invokes unregisterApp for empty
buffers) so stale app entries are not left in APPS_KEY.
🧹 Nitpick comments (14)
src/main/java/redot/redot_server/domain/eventlog/entity/EventType.java (1)
3-6: 주석을 Javadoc으로 이동하는 것을 고려해 주세요.각 상수의 의미를 설명하는 주석이 유용하지만, Javadoc 형식으로 변경하면 IDE 도움말과 API 문서에서도 활용 가능합니다.
♻️ 제안 수정
+/** + * 이벤트 로그 유형 + */ public enum EventType { - PAGE_VIEW, CTA_CLICK, PURCHASE - // 조회, 클릭, 구매 + /** 페이지 조회 */ + PAGE_VIEW, + /** CTA 클릭 */ + CTA_CLICK, + /** 구매 */ + PURCHASE }src/test/java/redot/redot_server/domain/eventlog/service/EventLogIngestServiceTest.java (1)
45-49: eventId와 occurredAt 필드 검증도 추가하면 좋습니다.현재 테스트는 핵심 필드를 검증하고 있지만,
eventId와occurredAt필드의 직렬화도 검증하면 전체 페이로드가 올바르게 생성되는지 확인할 수 있습니다.♻️ 제안 수정
String json = jsonCaptor.getValue(); assertThat(json).contains("\"redotAppId\":10"); assertThat(json).contains("\"deviceType\":\"MOBILE\""); assertThat(json).contains("\"ip\":\"127.0.0.1\""); + assertThat(json).contains("\"eventId\":"); + assertThat(json).contains("\"occurredAt\":"); }src/test/java/redot/redot_server/domain/eventlog/service/EventLogStoreTest.java (2)
78-96: 정상 케이스(size > 0) 테스트도 추가하면 좋습니다.null 반환 케이스만 테스트하고 있습니다. 정상적인 값 반환 케이스도 테스트하면 메서드 동작을 완전히 검증할 수 있습니다.
♻️ 제안 테스트 추가
`@Test` void size_returns_actual_size_when_not_null() { // given StringRedisTemplate template = mock(StringRedisTemplate.class); `@SuppressWarnings`("unchecked") ListOperations<String, String> listOps = mock(ListOperations.class); when(template.opsForList()).thenReturn(listOps); when(listOps.size("event-log:buffer:10")).thenReturn(5L); EventLogStore store = new EventLogStore(template); // when long size = store.size(10L); // then assertThat(size).isEqualTo(5L); }
55-73:getRegisteredApps()메서드의 null 엣지 케이스에 대한 테스트 추가를 권장합니다.
members()메서드가 null을 반환하는 경우에 대한 테스트가 부족합니다. 현재 구현(line 42)에서는if (members == null || members.isEmpty()) return List.of();로 null을 올바르게 처리하고 있으므로, 이 동작을 검증하는 테스트를 추가하면 테스트 커버리지가 향상됩니다.♻️ 제안 테스트
`@Test` void getRegisteredApps_returns_empty_list_when_members_is_null() { // given StringRedisTemplate template = mock(StringRedisTemplate.class); `@SuppressWarnings`("unchecked") SetOperations<String, String> setOps = mock(SetOperations.class); when(template.opsForSet()).thenReturn(setOps); when(setOps.members("event-log:apps")).thenReturn(null); EventLogStore store = new EventLogStore(template); // when List<Long> apps = store.getRegisteredApps(); // then assertThat(apps).isEmpty(); }build.gradle (1)
79-80: 의존성 중복 및 버전 일관성 검토 필요
PostgreSQL 드라이버 버전 불일치: Line 47에서
runtimeOnly 'org.postgresql:postgresql'은 Spring Boot BOM이 관리하는 버전을 사용하지만, Line 79에서는42.7.3을 명시적으로 지정했습니다. 버전 불일치가 발생할 수 있습니다.Flyway 중복: Line 29에 이미
implementation 'org.flywaydb:flyway-core'가 있으므로,testImplementation에 추가할 필요가 없습니다.implementation스코프는 테스트에서도 사용 가능합니다.♻️ 제안된 수정
- testImplementation "org.postgresql:postgresql:42.7.3" - testImplementation "org.flywaydb:flyway-core"PostgreSQL 드라이버가 테스트에 명시적으로 필요하다면, 버전 없이 BOM 관리 버전을 사용하세요:
+ testImplementation "org.postgresql:postgresql"src/main/java/redot/redot_server/domain/eventlog/service/EventLogIngestService.java (1)
21-28: 이벤트 손실 처리 전략 확인현재 JSON 직렬화 실패 시 로그만 남기고 조용히 반환합니다. 이벤트 로깅 특성상 fire-and-forget 패턴이 적절할 수 있지만, 이벤트 손실이 허용되는지 확인이 필요합니다.
만약 이벤트 신뢰성이 중요하다면, 호출자에게 실패를 알리는 방안을 고려해 주세요:
♻️ 선택적 개선안 (실패 전파가 필요한 경우)
- public void ingestPageView(PageViewCommand cmd) { + public boolean ingestPageView(PageViewCommand cmd) { try { String json = objectMapper.writeValueAsString(cmd); eventLogStore.pushPageView(cmd.redotAppId(), json); + return true; } catch (JsonProcessingException e) { log.error("Failed to serialize page view event. cmd={}", cmd, e); + return false; } }src/main/java/redot/redot_server/domain/eventlog/controller/EventLogController.java (1)
37-50:jwtPrincipal파라미터가 선언되었으나 사용되지 않음
jwtPrincipal이 주입되지만PageViewCommand생성 시 사용되지 않습니다. Issue#137에서user_id (nullable)필드를 요구하고 있으며, 회원/비회원 구분 메커니즘도 언급되어 있습니다.의도적으로 나중에 구현할 계획이라면 TODO 주석을 추가하거나, 현재 구현에서 사용자 식별이 필요하다면
PageViewCommand에userId필드를 추가하는 것을 고려해 주세요.src/main/java/redot/redot_server/domain/eventlog/entity/EventLogEntity.java (2)
9-19: 엔티티에 getter 메서드 누락
EventLogEntity에@Getter어노테이션이나 수동 getter 메서드가 없습니다. 이로 인해 저장된 데이터 검증, 로깅, 또는 향후 조회 API 구현 시 필드 접근이 불가능합니다.🔧 Lombok `@Getter` 추가 제안
import jakarta.persistence.*; +import lombok.Getter; import redot.redot_server.global.common.entity.BaseTimeEntity; `@Entity` +@Getter `@Table`(name = "event_logs",
36-44: 주석 처리된 코드 정리 필요
actorType,actorId,anonymousId관련 코드가 주석 처리되어 있습니다. 향후 구현 예정이라면 TODO 주석으로 명시하거나 별도 이슈로 추적하고, 현재 코드에서는 제거하는 것이 좋습니다.주석 처리된 코드는 코드베이스의 가독성을 저하시키고, 나중에 필요한 변경인지 실수로 남겨진 것인지 구분이 어렵습니다.
src/test/java/redot/redot_server/domain/eventlog/service/EventLogFlushSchedulerTest.java (1)
76-76: 매직 넘버 중복 - 상수 참조 고려
2000 - 1이 여러 테스트에서 하드코딩되어 있습니다.EventLogFlushScheduler.BATCH_SIZE가 변경되면 테스트가 실제 동작과 불일치하게 됩니다.상수를 패키지-프라이빗으로 노출하거나 테스트 내에서 공통 상수로 추출하는 것을 고려해 주세요.
src/main/java/redot/redot_server/domain/eventlog/service/EventLogFlushScheduler.java (1)
42-46: range()와 trim() 사이의 잠재적 경쟁 조건
range()로 데이터를 읽고trim()으로 삭제하는 사이에 새로운 이벤트가 push될 경우, 해당 이벤트가 의도치 않게 삭제될 수 있습니다.10분 간격 스케줄링으로 실제 발생 가능성은 낮지만, Redis MULTI/EXEC 트랜잭션 또는 Lua 스크립트를 사용한 원자적 연산을 고려해 볼 수 있습니다.
src/main/java/redot/redot_server/domain/eventlog/controller/docs/EventLogControllerDocs.java (2)
20-25: PageViewRequest가 OpenAPI 문서에서 숨겨져 있음
PageViewRequest파라미터가@Parameter(hidden = true)로 설정되어 API 클라이언트가 요청 본문 스키마를 확인할 수 없습니다.
@RequestBody어노테이션과 스키마 문서화를 추가하여 클라이언트 개발자가 필요한 필드를 알 수 있도록 해 주세요.🔧 RequestBody 문서화 제안
+import io.swagger.v3.oas.annotations.parameters.RequestBody; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; ResponseEntity<Void> pageView( `@Parameter`(hidden = true) Long redotAppId, - `@Parameter`(hidden = true) PageViewRequest req, + `@RequestBody`( + description = "페이지 뷰 이벤트 정보", + required = true, + content = `@Content`(schema = `@Schema`(implementation = PageViewRequest.class)) + ) PageViewRequest req, `@Parameter`(hidden = true) HttpServletRequest servletRequest, `@Parameter`(hidden = true) JwtPrincipal jwtPrincipal );
17-19: 에러 응답 문서화 누락202 성공 응답만 문서화되어 있습니다. 400 (잘못된 요청), 401 (인증 실패), 500 (서버 오류) 등의 에러 응답도 추가하면 API 사용자에게 도움이 됩니다.
src/main/java/redot/redot_server/domain/eventlog/service/EventLogStore.java (1)
15-16: 주석과 실제 TTL 값이 불일치합니다.주석에는 "10분 버퍼"라고 명시되어 있으나, 실제
BUFFER_TTL은 20분으로 설정되어 있습니다. 스케줄러가 10분마다 플러시한다면, 20분 TTL은 한 사이클을 놓치더라도 데이터가 유지되도록 하는 안전 마진으로 보입니다. 의도가 맞다면 주석을 명확히 수정해 주세요.💡 주석 수정 제안
- // 10분 버퍼 (스케줄러가 10분마다 비우는 구조) + // 스케줄러가 10분마다 비우므로, 1회 실패를 대비한 20분 TTL private static final Duration BUFFER_TTL = Duration.ofMinutes(20);
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (18)
.gitignorebuild.gradlesrc/main/java/redot/redot_server/domain/eventlog/controller/EventLogController.javasrc/main/java/redot/redot_server/domain/eventlog/controller/docs/EventLogControllerDocs.javasrc/main/java/redot/redot_server/domain/eventlog/dto/PageViewCommand.javasrc/main/java/redot/redot_server/domain/eventlog/dto/PageViewRequest.javasrc/main/java/redot/redot_server/domain/eventlog/entity/DeviceType.javasrc/main/java/redot/redot_server/domain/eventlog/entity/EventLogEntity.javasrc/main/java/redot/redot_server/domain/eventlog/entity/EventType.javasrc/main/java/redot/redot_server/domain/eventlog/entity/IdentityType.javasrc/main/java/redot/redot_server/domain/eventlog/repository/EventLogRepository.javasrc/main/java/redot/redot_server/domain/eventlog/service/EventLogFlushScheduler.javasrc/main/java/redot/redot_server/domain/eventlog/service/EventLogIngestService.javasrc/main/java/redot/redot_server/domain/eventlog/service/EventLogStore.javasrc/main/resources/application.ymlsrc/test/java/redot/redot_server/domain/eventlog/service/EventLogFlushSchedulerTest.javasrc/test/java/redot/redot_server/domain/eventlog/service/EventLogIngestServiceTest.javasrc/test/java/redot/redot_server/domain/eventlog/service/EventLogStoreTest.java
💤 Files with no reviewable changes (2)
- src/main/resources/application.yml
- .gitignore
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-12-17T01:39:43.440Z
Learnt from: eraser502
Repo: redotlabs/server PR: 134
File: src/main/java/redot/redot_server/domain/admin/service/AdminRedotAppService.java:58-71
Timestamp: 2025-12-17T01:39:43.440Z
Learning: In the RedotApp domain model, enforce 1:1 relationships: RedotApp must have exactly one Domain, one StyleInfo, and one SiteSetting. Review AdminRedotAppService and related domain entities to ensure constraints reflect this: enforce non-null associations, unique foreign keys or join tables as appropriate, and strict cascade rules. Validate that the database schema enforces one-to-one mappings (unique foreign keys or shared primary keys), and that service layer logic does not permit multiple related entities or optional links for RedotApp. Ensure getters/setters and persistence mappings (annotations or XML) align with a 1:1 relationship pattern and update tests to cover these invariants.
Applied to files:
src/main/java/redot/redot_server/domain/eventlog/entity/IdentityType.javasrc/main/java/redot/redot_server/domain/eventlog/repository/EventLogRepository.javasrc/main/java/redot/redot_server/domain/eventlog/entity/EventLogEntity.javasrc/main/java/redot/redot_server/domain/eventlog/entity/DeviceType.javasrc/main/java/redot/redot_server/domain/eventlog/service/EventLogIngestService.javasrc/main/java/redot/redot_server/domain/eventlog/controller/EventLogController.javasrc/main/java/redot/redot_server/domain/eventlog/service/EventLogStore.javasrc/main/java/redot/redot_server/domain/eventlog/dto/PageViewRequest.javasrc/main/java/redot/redot_server/domain/eventlog/service/EventLogFlushScheduler.javasrc/main/java/redot/redot_server/domain/eventlog/entity/EventType.javasrc/main/java/redot/redot_server/domain/eventlog/controller/docs/EventLogControllerDocs.javasrc/main/java/redot/redot_server/domain/eventlog/dto/PageViewCommand.java
🧬 Code graph analysis (1)
src/main/java/redot/redot_server/domain/eventlog/service/EventLogFlushScheduler.java (1)
src/main/java/redot/redot_server/domain/eventlog/service/EventLogStore.java (1)
Component(11-76)
🔇 Additional comments (12)
src/main/java/redot/redot_server/domain/eventlog/entity/IdentityType.java (1)
1-5: LGTM!Issue
#137의회원/비회원 구분 요구사항에 맞춰 적절히 정의되었습니다. 현재 EventLogEntity에서 actor 관련 필드가 주석 처리되어 있으나, 향후 확장 시 활용될 예정입니다.src/main/java/redot/redot_server/domain/eventlog/entity/DeviceType.java (1)
1-7: LGTM!Issue
#137요구사항에 명시된 device_type 스펙(MOBILE, DESKTOP, TABLET)과 정확히 일치합니다.src/test/java/redot/redot_server/domain/eventlog/service/EventLogStoreTest.java (1)
21-50: LGTM!
pushPageView메서드의 핵심 동작(앱 등록, 페이로드 푸시, TTL 설정)을 철저하게 검증하고 있습니다. given/when/then 구조가 명확하고 읽기 쉽습니다.src/main/java/redot/redot_server/domain/eventlog/repository/EventLogRepository.java (1)
7-9: LGTM!표준 Spring Data JPA 레포지토리로 적절하게 구현되었습니다.
JpaRepository의saveAll()메서드가 배치 저장에 활용될 수 있어 PR 요구사항에 부합합니다.참고:
@Repository어노테이션은 Spring Data JPA가 자동으로 감지하므로 선택사항이지만, 명시적으로 표기하는 것도 괜찮습니다.src/main/java/redot/redot_server/domain/eventlog/dto/PageViewRequest.java (1)
6-9: LGTM!
deviceType만 클라이언트에서 받고, 나머지 필드(appId, ip 등)는 서버에서 컨텍스트로 추출하는 설계가 적절합니다.@NotNull검증도 올바르게 적용되었습니다.주석으로 남긴
anonymousId는 향후 비회원 추적 기능 확장 시 고려할 수 있겠습니다.src/main/java/redot/redot_server/domain/eventlog/dto/PageViewCommand.java (1)
8-17: LGTM!이벤트 로그에 필요한 필드들이 적절하게 정의되었습니다.
UUID eventId로 이벤트 고유성을 보장하고,Instant occurredAt으로 타임존 독립적인 타임스탬프를 사용한 점이 좋습니다.주석 처리된 actor 관련 필드는 향후 회원/비회원 구분 기능 구현 시 활성화할 수 있겠습니다.
src/main/java/redot/redot_server/domain/eventlog/service/EventLogIngestService.java (1)
14-16: LGTM!
@RequiredArgsConstructor를 통한 생성자 주입과ObjectMapper활용이 적절합니다. Spring Boot가 자동 구성하는ObjectMapper빈을 주입받아 사용하므로 일관된 직렬화 설정이 적용됩니다.build.gradle (1)
70-72: Jackson JSR310 의존성 추가는 필수입니다Spring Boot 3.x의 Jackson 자동 설정은
jackson-datatype-jsr310의존성이 클래스패스에 존재할 때만 작동합니다. 이 의존성이 없으면java.time타입의 직렬화가 올바르게 처리되지 않습니다. 현재 코드베이스에서java.time타입을 사용하고 있으므로 이 의존성 추가는 불필요하지 않으며, 오히려 필수적입니다.Likely an incorrect or invalid review comment.
src/main/java/redot/redot_server/domain/eventlog/controller/EventLogController.java (1)
56-62: X-Forwarded-For 헤더 스푸핑 가능성 검토 필요
X-Forwarded-For헤더는 클라이언트가 임의로 조작할 수 있어, 신뢰할 수 있는 프록시/로드밸런서가 아닌 경우 IP 스푸핑에 취약할 수 있습니다. 프로덕션 환경에서 신뢰할 수 있는 프록시 설정이 되어 있는지 확인해 주세요.현재 구현은 일반적인 패턴을 따르고 있으나, 분석 데이터의 정확성이 중요하다면 Spring의
ForwardedHeaderFilter또는 애플리케이션 서버 레벨에서의 신뢰할 수 있는 프록시 설정을 검토하시기 바랍니다.src/test/java/redot/redot_server/domain/eventlog/service/EventLogFlushSchedulerTest.java (1)
61-90: 테스트 케이스 구조 적절함Redis에서 읽기, DB 저장, 버퍼 trim까지의 전체 플로우를 잘 검증하고 있습니다.
ArgumentCaptor를 사용한 저장 데이터 검증도 좋은 접근입니다.src/main/java/redot/redot_server/domain/eventlog/service/EventLogStore.java (2)
29-35: 구현이 적절합니다.
rightPush와expire가 원자적이지 않지만, TTL은 정리 목적이므로 치명적이지 않습니다. 다만, 고트래픽 환경에서 성능 최적화가 필요하다면 Redis 파이프라인이나 Lua 스크립트를 고려해 볼 수 있습니다.
49-75: 나머지 메서드들은 적절하게 구현되어 있습니다.
registerApp: SET add 연산으로 멱등성 보장unregisterApp: 버퍼는 TTL로 자동 정리되므로 현재 구현이 합리적size: null-safe 처리 완료bufferKey: 키 패턴 생성 정상
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
src/main/java/redot/redot_server/domain/eventlog/service/EventLogFlushScheduler.java
Show resolved
Hide resolved
src/main/java/redot/redot_server/domain/eventlog/service/EventLogFlushScheduler.java
Outdated
Show resolved
Hide resolved
src/main/java/redot/redot_server/domain/eventlog/service/EventLogFlushScheduler.java
Outdated
Show resolved
Hide resolved
src/main/java/redot/redot_server/domain/eventlog/service/EventLogStore.java
Show resolved
Hide resolved
| public List<Long> getRegisteredApps() { | ||
| Set<String> members = stringRedisTemplate.opsForSet().members(APPS_KEY); | ||
| if (members == null || members.isEmpty()) return List.of(); | ||
| return members.stream().map(Long::valueOf).toList(); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Long::valueOf 파싱 시 예외 처리가 누락되었습니다.
Redis에 잘못된 데이터가 저장되어 있을 경우 NumberFormatException이 발생하여 플러시 스케줄러 전체가 실패할 수 있습니다. 방어적 파싱을 권장합니다.
🛡️ 방어적 파싱 적용 제안
public List<Long> getRegisteredApps() {
Set<String> members = stringRedisTemplate.opsForSet().members(APPS_KEY);
if (members == null || members.isEmpty()) return List.of();
- return members.stream().map(Long::valueOf).toList();
+ return members.stream()
+ .filter(s -> s != null && s.matches("\\d+"))
+ .map(Long::valueOf)
+ .toList();
}🤖 Prompt for AI Agents
In `@src/main/java/redot/redot_server/domain/eventlog/service/EventLogStore.java`
around lines 40 - 44, getRegisteredApps currently maps Redis string members to
Long using Long::valueOf without handling NumberFormatException; wrap parsing in
defensive logic inside getRegisteredApps (using
stringRedisTemplate.opsForSet().members(APPS_KEY)) to skip or filter out
non-numeric values by attempting Long.parseLong/Long.valueOf in a try/catch per
item, log a warning including the offending value when parsing fails, and return
only successfully parsed Longs (empty list if none).
src/test/java/redot/redot_server/domain/eventlog/service/EventLogIngestServiceTest.java
Outdated
Show resolved
Hide resolved
…tive apps, and tests
…ate db dependencies
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@20210815
한 가지 리뷰 사항만 확인해주시면 될 것 같아요!
고생 많으셨습니다 👍
| ); | ||
|
|
||
| ingestService.ingestPageView(cmd); | ||
| return ResponseEntity.accepted().build(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
제가 생각했던 구조는 엔드포인트를 /event와 같이 구성하여 body에 event_type을 주입하도록 일반화하는 구조였어요.
지금과 같은 방식이라면 이벤트 타입이 추가될 때마다 엔드포인트가 추가돼야 하기 때문에 일반화해주시면 감사하겠습니다!
Overview
Related Issue
PR Checklist
Additional Information