Skip to content

[Feat] Embedding Job 상태 전이 이벤트 발행 및 대시보드 구독 #151

Description

@kangcheolung

📌 Description

Worker가 만드는 PENDING → PROCESSING → INDEXED/FAILED 상태 전이를 대시보드가 새로고침 없이 실시간 반영하도록, A 담당자 소유 embedding 도메인 코드에 이벤트 발행 훅을 추가하고 대시보드가 이를 구독합니다.

이벤트 하나마다 즉시 push하면 다건 상태 전이가 몰리는 burst 상황(예: 이슈3의 retry-all, 또는 embedding API 장애로 여러 job이 한꺼번에 실패하는 상황)에서 오히려 폴링보다 DB를 더 많이 두드리게 되므로, dirty flag + 짧은 주기 스케줄러 기반 debounce/coalesce를 함께 구현합니다.

A 담당자 코드 변경이 포함되어 있어 조율/리뷰가 필요합니다.

✅ To-do

  • EmbeddingJobStatusChangedEvent(가칭) 이벤트 클래스 정의 (embedding 도메인 내)
  • EmbeddingJobClaimService.claim() 성공 시 이벤트 발행 추가 (PENDING → PROCESSING)
  • DocumentIndexingCompletionService.complete()에 이벤트 발행 추가 (PROCESSING → INDEXED)
  • DocumentIndexingFailureService.fail()에 이벤트 발행 추가 (재시도 예약/최종실패 모두)
  • dashboard 도메인에 @TransactionalEventListener(phase = AFTER_COMMIT) 리스너 구현 — 단, 즉시 sendDashboardUpdate() 호출하지 않고 dirty flag만 세움
  • 짧은 시간 내 다건 이벤트 발생 시 debounce/coalesce 처리 (dirty flag + 짧은 주기(예: 300ms) 스케줄러로 burst 상황에서도 push당 1회 집계만 계산 — DB 부하 최소화 원칙 유지, 이슈2의 "1초 이내 전달" SLA 안에 여유 있게 들어옴)
  • debounce 검증 통합 테스트: Hibernate Statistics(getPrepareStatementCount()) + Awaitility로 burst 시 쿼리 수가 1회 집계분(약 9개: documents 3 + jobs 4 + workers 1 + search 1) 수준으로 억제되는지 확인
    • 이벤트 발행은 Propagation.REQUIRES_NEW 트랜잭션으로 각각 독립 커밋시켜야 AFTER_COMMIT이 매번 발화함 (바깥 트랜잭션에 그냥 참여시키면 한 번의 커밋으로 묶여 burst 자체가 재현 안 됨)
    • getQueryExecutionCount()가 아니라 getPrepareStatementCount() 사용 — findAverageProcessingMillis()가 native query라 JPQL 카운터엔 안 잡힐 수 있음
    • statistics.clear()는 데이터 세팅(job insert 등) 완료 후, burst 트리거 직전에 호출 — @BeforeEach에서만 clear하면 세팅 쿼리까지 카운트에 섞임
  • testImplementation 'org.awaitility:awaitility' 의존성 추가
  • AFTER_COMMIT 리스너 통합 테스트 시 기본 rollback 동작 주의 — 테스트 메서드에 @Transactional을 붙이지 않고 기존 통합 테스트 패턴(TRUNCATE 기반 정리)을 따르거나, 불가피하면 @Commit/TestTransaction으로 명시적 커밋
  • 통합 테스트로 상태 전이 시 push 확인

✅ 완료 기준

  • Worker의 Job Claim/완료/실패 시점에, 트랜잭션 커밋 이후에만 대시보드가 즉시(최대 debounce 주기만큼 지연) 갱신된다
  • 트랜잭션 롤백 시에는 push가 발생하지 않는다
  • burst 상황(다건 상태 전이가 짧은 시간 내 발생)에서도 집계 쿼리는 debounce 주기당 1회 수준으로 억제된다
  • embedding 도메인이 dashboard 패키지를 import하지 않는다 (의존 방향: dashboard → embedding만 허용)

📒 기타

  • 선행 이슈: #이슈2 (WebSocket 인프라)
  • A 담당자 리뷰 필요 (embedding 도메인 command 서비스 3곳 변경)
  • 시연 시나리오: 깨진 파일 업로드 → FAILED → 재처리 → PENDING→PROCESSING→INDEXED 실시간 반영 확인
  • debounce는 push 자체를 없애는 게 아니라 "이벤트 받을 때마다 즉시 push"를 "짧은 주기 스케줄러가 모아서 한 번 push"로 트리거 방식만 바꾸는 것 — WebSocket/STOMP 인프라(이슈2)는 그대로 재사용함
  • ArchUnit으로 embedding → dashboard 역방향 의존을 자동 검증하는 룰 추가는 선택사항, 여유 있으면 마지막에 적용

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions