[Feat] Embedding Job 상태 전이 이벤트 발행 및 대시보드 구독 - #152
Conversation
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ingConfig) 구현 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Warning Review limit reached
Next review available in: 44 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (4)
📝 WalkthroughWalkthrough임베딩 작업의 Claim·Completion·Failure 상태 전이가 이벤트를 발행합니다. 커밋 후 리스너가 dirty 플래그를 설정합니다. debounce 스케줄러가 최신 집계를 Changes임베딩 상태 이벤트 발행
대시보드 debounce 갱신
통합 검증
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant EmbeddingJobStatusService
participant ApplicationEventPublisher
participant EmbeddingJobStatusChangedEventListener
participant DashboardUpdateFlag
participant DashboardPushScheduler
participant WebSocket
EmbeddingJobStatusService->>ApplicationEventPublisher: 상태 변경 이벤트 발행
ApplicationEventPublisher->>EmbeddingJobStatusChangedEventListener: 커밋 후 이벤트 전달
EmbeddingJobStatusChangedEventListener->>DashboardUpdateFlag: markDirty()
DashboardPushScheduler->>DashboardUpdateFlag: consumeIfDirty()
DashboardPushScheduler->>WebSocket: 최신 대시보드 집계 전송
Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 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: 4
🧹 Nitpick comments (1)
src/test/java/com/opensource/docgrid/domain/embedding/service/command/DocumentIndexingCompletionServiceTest.java (1)
76-76: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win세 단위 테스트가 이벤트 발행 계약을 검증하지 않습니다.
세 파일 모두
ApplicationEventPublisherMock만 주입합니다.publishEvent(...)가 호출되지 않아도 테스트가 통과합니다.
- src/test/java/com/opensource/docgrid/domain/embedding/service/command/DocumentIndexingCompletionServiceTest.java#L76-L76: 완료 성공 시
EmbeddingJobStatusChangedEvent.jobId()를 검증하고, 완료 재생 시 재발행하지 않는지 확인하세요.- src/test/java/com/opensource/docgrid/domain/embedding/service/command/DocumentIndexingFailureServiceTest.java#L79-L79: 재시도 예약과 최종 실패 시 이벤트를 검증하고, 실패 재생 시 중복 발행하지 않는지 확인하세요.
- src/test/java/com/opensource/docgrid/domain/embedding/service/command/EmbeddingJobClaimServiceTest.java#L63-L63: 정상 Claim 시 이벤트를 검증하고, Claim 대상이 없을 때는 발행하지 않는지 확인하세요.
검증 예시
+then(applicationEventPublisher).should() + .publishEvent(new EmbeddingJobStatusChangedEvent(JOB_ID));As per path instructions,
src/test/**/*.java는 테스트 커버리지, 스프링 테스트 어노테이션, mock 사용법을 확인해야 합니다.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/test/java/com/opensource/docgrid/domain/embedding/service/command/DocumentIndexingCompletionServiceTest.java` at line 76, 세 단위 테스트가 ApplicationEventPublisher.publishEvent 호출 계약을 검증하도록 보강하세요. src/test/java/com/opensource/docgrid/domain/embedding/service/command/DocumentIndexingCompletionServiceTest.java 76-76에서는 성공 완료 이벤트의 EmbeddingJobStatusChangedEvent.jobId()를 검증하고 재생 시 재발행되지 않음을 확인하세요. src/test/java/com/opensource/docgrid/domain/embedding/service/command/DocumentIndexingFailureServiceTest.java 79-79에서는 재시도 예약 및 최종 실패 이벤트를 검증하고 실패 재생 시 중복 발행이 없음을 확인하세요. src/test/java/com/opensource/docgrid/domain/embedding/service/command/EmbeddingJobClaimServiceTest.java 63-63에서는 정상 Claim 이벤트를 검증하고 Claim 대상이 없을 때 publishEvent가 호출되지 않음을 검증하세요.Source: Path instructions
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/design/kangcheolung-`#151-ragops-dashboard-realtime-update.md:
- Line 106: markdownlint MD040 경고를 해결하도록
docs/design/kangcheolung-#151-ragops-dashboard-realtime-update.md의 106-106 아키텍처
다이어그램 펜스와 335-335 흐름 예시 펜스에 text 언어 식별자를 지정하세요.
In
`@src/main/java/com/opensource/docgrid/domain/dashboard/event/DashboardPushScheduler.java`:
- Around line 19-22: DashboardPushScheduler의 클래스 주석에서 비공개 순번 라벨인 “(이슈1)”과
“(이슈2)”를 제거하고, 각각 “대시보드 집계 조회”와 “WebSocket 전송” 같은 설명형 이름으로 교체하세요.
- Around line 41-44: DashboardPushScheduler의 consumeIfDirty() 블록에서 getSummary()
또는 sendDashboardUpdate()가 실패하면 예외를 다시 전파하기 전에 dashboardUpdateFlag.markDirty()를
호출해 dirty 상태를 복구하세요. 정상적인 push 경로는 기존 동작을 유지하고, 이 예외 경로를 검증하는 단위 테스트를 추가하세요.
In
`@src/test/java/com/opensource/docgrid/domain/dashboard/event/DashboardPushDebounceIntegrationTest.java`:
- Around line 113-118: 강화된 대시보드 집계 검증을 위해 DashboardQueryService.getSummary() 호출
횟수를 계측하고 정확히 한 번인지 검증하세요. 이벤트 발행이 완료된 뒤 최소 한 debounce 주기 이상 대기한 후 단일 호출 조건을
확인하도록 await/assertion 흐름을 변경하고, 기존 prepare statement 수 기반의 느슨한 검증은 제거하거나 보조 검증으로
대체하세요.
---
Nitpick comments:
In
`@src/test/java/com/opensource/docgrid/domain/embedding/service/command/DocumentIndexingCompletionServiceTest.java`:
- Line 76: 세 단위 테스트가 ApplicationEventPublisher.publishEvent 호출 계약을 검증하도록 보강하세요.
src/test/java/com/opensource/docgrid/domain/embedding/service/command/DocumentIndexingCompletionServiceTest.java
76-76에서는 성공 완료 이벤트의 EmbeddingJobStatusChangedEvent.jobId()를 검증하고 재생 시 재발행되지 않음을
확인하세요.
src/test/java/com/opensource/docgrid/domain/embedding/service/command/DocumentIndexingFailureServiceTest.java
79-79에서는 재시도 예약 및 최종 실패 이벤트를 검증하고 실패 재생 시 중복 발행이 없음을 확인하세요.
src/test/java/com/opensource/docgrid/domain/embedding/service/command/EmbeddingJobClaimServiceTest.java
63-63에서는 정상 Claim 이벤트를 검증하고 Claim 대상이 없을 때 publishEvent가 호출되지 않음을 검증하세요.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: d61ea00d-9475-4f41-a3b8-d878035c9bc4
📒 Files selected for processing (19)
build.gradledocs/design/kangcheolung-#151-ragops-dashboard-realtime-update.mdsrc/main/java/com/opensource/docgrid/domain/dashboard/config/DashboardSchedulingConfig.javasrc/main/java/com/opensource/docgrid/domain/dashboard/event/DashboardPushScheduler.javasrc/main/java/com/opensource/docgrid/domain/dashboard/event/DashboardUpdateFlag.javasrc/main/java/com/opensource/docgrid/domain/dashboard/event/EmbeddingJobStatusChangedEventListener.javasrc/main/java/com/opensource/docgrid/domain/embedding/event/EmbeddingJobStatusChangedEvent.javasrc/main/java/com/opensource/docgrid/domain/embedding/service/command/DocumentIndexingCompletionService.javasrc/main/java/com/opensource/docgrid/domain/embedding/service/command/DocumentIndexingFailureService.javasrc/main/java/com/opensource/docgrid/domain/embedding/service/command/EmbeddingJobClaimService.javasrc/main/resources/application.ymlsrc/test/java/com/opensource/docgrid/domain/dashboard/event/DashboardPushDebounceIntegrationTest.javasrc/test/java/com/opensource/docgrid/domain/dashboard/event/DashboardPushSchedulerTest.javasrc/test/java/com/opensource/docgrid/domain/dashboard/event/DashboardUpdateFlagTest.javasrc/test/java/com/opensource/docgrid/domain/dashboard/event/EmbeddingJobStatusChangedAfterCommitIntegrationTest.javasrc/test/java/com/opensource/docgrid/domain/dashboard/event/EmbeddingJobStatusChangedEventListenerTest.javasrc/test/java/com/opensource/docgrid/domain/embedding/service/command/DocumentIndexingCompletionServiceTest.javasrc/test/java/com/opensource/docgrid/domain/embedding/service/command/DocumentIndexingFailureServiceTest.javasrc/test/java/com/opensource/docgrid/domain/embedding/service/command/EmbeddingJobClaimServiceTest.java
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Summary
EmbeddingJobClaimService/DocumentIndexingCompletionService/DocumentIndexingFailureService(A 담당자 소유) 세 지점에EmbeddingJobStatusChangedEvent발행 한 줄씩만 추가 — 상태 전환 로직 자체는 전혀 변경하지 않음dashboard가 아닌embedding패키지에 정의 (dashboard → embedding단방향 의존 유지, A 소유 코드가 B 패키지를 import하지 않도록)@TransactionalEventListener(phase = AFTER_COMMIT)로 구독 — 발행 Transaction이 실제로 커밋된 경우에만 반응, 롤백 시 push 없음DashboardUpdateFlag(AtomicBoolean) +DashboardPushScheduler(300ms 주기,fixedDelayString) 조합으로 debounce — burst 상황(retry-all, 다건 장애)에서 이벤트 개수만큼 집계 쿼리가 느는 것을 방지indexing.worker.enabled(기본 false) 설정과 무관하게 항상 동작해야 하므로, 조건 없는DashboardSchedulingConfig를 별도로 추가 (기존WorkerSchedulingConfig의@EnableScheduling은 조건부라 얹혀가면 안 됨)설계 결정 — debounce 근거
burst 상황에서 이벤트마다 즉시
getSummary()(약 9개 쿼리)를 재계산하면 27건 burst에서 27 × 9 ≈ 243개 쿼리가 몰릴 수 있습니다.DashboardUpdateFlag.consumeIfDirty()(check-and-clear를compareAndSet으로 원자화)와 짧은 주기 스케줄러 조합으로, 몇 번의 상태 전이가 몰리든 debounce 주기당 최대 1회(9개 안팎)로 억제됩니다. 이 수치는 HibernateStatistics.getPrepareStatementCount()로 통합 테스트에서 실측 검증했습니다. 상세 근거는docs/design/kangcheolung-#151-ragops-dashboard-realtime-update.md3장·5장 참고.Test plan
DashboardUpdateFlagTest— markDirty/consumeIfDirty 원자성, 다건 markDirty coalesce, 초기 상태 검증 (단위 테스트 3건)EmbeddingJobStatusChangedEventListenerTest— 이벤트 수신 시 플래그만 세우고 그 외 상호작용 없음 검증 (단위 테스트 1건)DashboardPushSchedulerTest— dirty일 때만 집계·push, dirty 아니면 무상호작용 검증 (단위 테스트 2건)EmbeddingJobClaimServiceTest/DocumentIndexingCompletionServiceTest/DocumentIndexingFailureServiceTest— 생성자 시그니처 변경(ApplicationEventPublisher추가)에 따른 Mock 반영, 기존 회귀 유지DashboardPushDebounceIntegrationTest— 27개 이벤트를REQUIRES_NEW로 각각 독립 커밋시켜 실제 burst 재현, Hibernate Statistics + Awaitility로 쿼리 수가<20(예상 243이 아님) 수준으로 억제됨을 실측EmbeddingJobStatusChangedAfterCommitIntegrationTest— 실제 STOMP Client로 (1) 커밋 시 push 도착, (2) 롤백 시 800ms(=debounce 4주기 이상) 대기해도 push 없음을 종단 검증./gradlew build전체 회귀 테스트 통과 — 총 769개, failures 0, errors 0상세 설계
docs/design/kangcheolung-#151-ragops-dashboard-realtime-update.mdcloses #151
🤖 Generated with Claude Code
Summary by CodeRabbit
새 기능
테스트