Skip to content

refactor/24, 25 - 트랜잭션 아웃박스 패턴 적용 및 스케줄러 구현 - #32

Merged
ji-circle merged 6 commits into
devfrom
refactor/24-apply-outbox-pattern-inv
May 14, 2026
Merged

refactor/24, 25 - 트랜잭션 아웃박스 패턴 적용 및 스케줄러 구현#32
ji-circle merged 6 commits into
devfrom
refactor/24-apply-outbox-pattern-inv

Conversation

@ji-circle

@ji-circle ji-circle commented May 13, 2026

Copy link
Copy Markdown
Contributor

📝 작업 내용

이번 PR에서 작업한 내용을 설명해주세요.

  • StockCommandService 등 주요 도메인 로직에서 KafkaTemplate 직접 의존성 제거
  • 트랜잭션 경계와 이벤트 발행을 분리하기 위한 InventoryOutbox 엔티티 및 Repository 구축
  • InventoryOutboxHelper를 통한 비즈니스 로직과 이벤트 적재 트랜잭션 동기화
  • 5초 주기 InventoryOutboxScheduler 구현
  • JSON 직렬화/역직렬화 오류 방지를 위해 스케줄러 내 DTO 복원(deserializePayload?) 로직 적용

🚀 주요 변경 사항

완료한 이슈 번호
Close #24 , Close #25
관련된 이슈 번호 (닫고 싶지 않은 경우)
Related to #

✅ 자체 체크리스트 (필수)

  • ./gradlew build 실행 결과 정상 (인증샷 첨부)
  • IntelliJ HTTP Client 테스트 완료 (인증샷 첨부)
  • 팀 내 컨벤션 준수 및 불필요한 로그, import 제거
  • 중요한 변경 사항이 팀에 공유되었는지

📸 테스트 인증샷

빌드 결과 및 IntelliJ HTTP Client 실행 화면을 여기에 첨부해 주세요.

스크린샷 2026-05-13 오전 3 54 31 스크린샷 2026-05-13 오전 3 54 40

💬 리뷰어 전달사항 (선택)

특별히 봐주었으면 하는 부분이나 논의가 필요한 점을 적어주세요.



📎 참고 자료

관련 문서, 레퍼런스 링크 등이 있다면 여기에 첨부해주세요.

Summary by CodeRabbit

  • 새로운 기능

    • POST /internal/scheduler/trigger-outbox 엔드포인트 추가
    • 수동 트리거 및 주기(5초) 기반 아웃박스 발행 스케줄러 도입
  • 개선 사항

    • 이벤트 발행을 아웃박스 기반으로 전환해 신뢰성·재시도·상태 관리 강화
    • 실패 카운트·영구 실패 처리 및 Kafka DLT 라우팅/에러 처리 개선
  • 테스트

    • 테스트 스크립스가 아웃박스 흐름 및 수동 트리거를 검증하도록 갱신
  • 구성

    • 아웃박스 최대 재시도 설정 추가 (기본 3)

Review Change Stack

- StockCommandService 등 주요 도메인 로직에서 KafkaTemplate 직접 의존성 제거
- 트랜잭션 경계와 이벤트 발행을 분리하기 위한 InventoryOutbox 엔티티 및 Repository 구축
- InventoryOutboxHelper를 통한 비즈니스 로직과 이벤트 적재 트랜잭션 동기화
- 5초 주기 InventoryOutboxScheduler 구현
- JSON 직렬화/역직렬화 오류 방지를 위해 스케줄러 내 DTO 복원(deserializePayload?) 로직 적용
@coderabbitai

coderabbitai Bot commented May 13, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 98c412d0-4022-4567-98c9-39f5b4d3872c

📥 Commits

Reviewing files that changed from the base of the PR and between 8f7f9c7 and f290957.

📒 Files selected for processing (1)
  • src/main/java/com/michelet/inventory/application/InventoryOutboxHelper.java

📝 Walkthrough

Walkthrough

Kafka 직접 발행과 after‑commit 동기화를 제거하고, 도메인 이벤트를 트랜잭션 내부에서 DB outbox에 적재한 뒤 폴링 스케줄러가 Kafka로 릴레이하도록 리팩터링합니다.

Changes

Outbox 패턴 도입 및 이벤트 릴레이

Layer / File(s) Summary
Outbox 엔티티·설정·JPA 선언
src/main/java/com/michelet/inventory/domain/model/InventoryOutbox.java, src/main/java/com/michelet/inventory/domain/model/OutboxStatus.java, src/main/java/com/michelet/inventory/infrastructure/repository/JpaInventoryOutboxRepository.java, src/main/resources/application.yml
InventoryOutbox 엔티티(재시도 카운트·버전·상태 전환 메서드 포함)와 OutboxStatus enum, top-50 조회 JPA 리포지토리 선언 및 inventory.outbox.max-retries/consumer retry 설정을 추가했습니다.
Outbox Helper - 이벤트 기록·상태/실패 처리
src/main/java/com/michelet/inventory/application/InventoryOutboxHelper.java
append(...)로 입력 검증·JSON 직렬화 후 outbox 저장(Propagation.MANDATORY), markAsPublished(UUID)handleFailure(UUID)를 REQUIRES_NEW 트랜잭션으로 구현하고 maxRetries를 검증합니다.
Outbox 폴링 스케줄러 및 Kafka 릴레이
src/main/java/com/michelet/inventory/application/InventoryOutboxScheduler.java, src/main/java/com/michelet/inventory/presentation/SchedulerTriggerController.java, api-test/inventory.http
5초 고정 지연 스케줄러가 INIT 상태 최대 50건을 폴링해 이벤트 타입별 DTO 역직렬화 후 Kafka로 비동기 전송하고, 성공 시 PUBLISHED로 표시하거나 실패 시 실패 핸들러를 호출합니다. 수동 트리거 엔드포인트와 API 테스트의 토큰 갱신·트리거 호출이 추가되었습니다.
도메인 레포지토리 구현
src/main/java/com/michelet/inventory/domain/repository/InventoryOutboxRepository.java, src/main/java/com/michelet/inventory/infrastructure/repository/InventoryOutboxRepositoryImpl.java
도메인 레포지토리 인터페이스와 JPA 위임 구현을 추가했습니다 (save, findById, findTop50ByStatusOrderByCreatedAtAsc).
서비스들의 outbox 전환
src/main/java/com/michelet/inventory/application/StockCommandService.java, src/main/java/com/michelet/inventory/application/ProductCommandService.java, src/main/java/com/michelet/inventory/application/ExhibitionSchedulerService.java, src/main/java/com/michelet/inventory/application/StockSchedulerService.java
기존 KafkaTemplate/TransactionSynchronizationManager 기반 after‑commit 발행을 제거하고, 트랜잭션 내부에서 outboxHelper.append(...)로 모든 이벤트(PRODUCT_CREATED/UPDATED/STATUS_CHANGED, STOCK_RESERVED/RESTORED, DailyStockReset 등)를 기록하도록 변경했습니다.
Kafka 구성 재배치
src/main/java/com/michelet/inventory/infrastructure/config/KafkaConfig.java
DeadLetterPublishingRecoverer의 DLT 라우팅과 DefaultErrorHandler 재구성, DLT 전용 listener factory 추가 및 consumer retry 설정 외부화가 적용되었습니다.
컨트롤러·테스트·API 테스트
src/main/java/com/michelet/inventory/presentation/SchedulerTriggerController.java, src/test/java/com/michelet/inventory/application/ProductCommandServiceTest.java, src/test/java/com/michelet/inventory/application/StockCommandServiceTest.java, api-test/inventory.http
POST /internal/scheduler/trigger-outbox 엔드포인트 추가. 단위 테스트는 Kafka 모킹을 제거하고 InventoryOutboxHelper 모킹으로 append 호출을 검증하며, API 테스트는 내부 토큰 갱신 후 outbox 트리거 호출을 추가했습니다.

Sequence Diagram(s)

sequenceDiagram
  participant API as SchedulerTriggerController
  participant Scheduler as InventoryOutboxScheduler
  participant Repo as InventoryOutboxRepository
  participant Helper as InventoryOutboxHelper
  participant Kafka as KafkaTemplate

  API->>Scheduler: processOutboxEvents() (manual trigger)
  Scheduler->>Repo: findTop50ByStatusOrderByCreatedAtAsc(INIT)
  Repo-->>Scheduler: pending outbox events
  loop each outbox event
    Scheduler->>Scheduler: deserializePayload(eventType, payload)
    Scheduler->>Kafka: send(topic, dto) (async .whenComplete)
    Kafka-->>Scheduler: send result (success/failure)
    alt success
      Scheduler->>Helper: markAsPublished(outboxId)
      Helper->>Repo: save(status=PUBLISHED) [REQUIRES_NEW]
    else failure
      Scheduler->>Helper: handleFailure(outboxId)
    end
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • Miche-Let/inventory-service#8: StockCommandService의 reserve 흐름과 이벤트 발행 방식(직접 Kafka vs outbox) 관련 변경이 겹칩니다.
  • Miche-Let/inventory-service#12: Stock 리스토어/리저브 경로의 이벤트 발행 방식과 관련된 변경 사항이 중복될 수 있습니다.
  • Miche-Let/inventory-service#31: StockCommandService의 reserve/restore 리팩터링과 메시징 처리 방식이 코드 수준에서 연관됩니다.

Suggested reviewers

  • githyj-jang
  • qldo
  • Sehi55
  • Jinyoung-Kim96
  • jihxonx

Poem

나는 토끼, 깡총깡총 달려왔네,
작은 이벤트를 DB에 살포시 숨겼네.
스케줄러가 와서 하나씩 꺼내면,
카프카로 안전히 전해지네. 🐇✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 41.46% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목은 'refactor/24, 25 - 트랜잭션 아웃박스 패턴 적용 및 스케줄러 구현'으로 변경 사항의 핵심(Transactional Outbox 패턴 도입과 스케줄러 구현)을 명확하게 요약하고 있습니다.
Linked Issues check ✅ Passed PR은 #24의 Outbox 엔티티/리포지토리 생성, afterCommit 훅 제거, 트랜잭션 내부 이벤트 적재 요구사항을 모두 충족하며, #25의 InventoryOutboxScheduler 구현(5초 폴링), PENDING 상태 관리, Kafka 발행 로직도 완전히 구현했습니다.
Out of Scope Changes check ✅ Passed 모든 변경 사항이 Outbox 패턴 도입과 스케줄러 구현이라는 명확한 범위 내에 있으며, KafkaConfig의 DLT 및 에러 핸들러 개선도 Kafka 안정성 강화로 관련성 있는 범위 내 변경입니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/24-apply-outbox-pattern-inv

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

coderabbitai[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

@ji-circle

This comment was marked as resolved.

@coderabbitai

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

@Jinyoung-Kim96 Jinyoung-Kim96 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

확인했습니다.

@qldo qldo left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

확인하였습니다

@ji-circle
ji-circle merged commit 2bd796b into dev May 14, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

3 participants