Skip to content

Conversation

@Jjiggu
Copy link
Contributor

@Jjiggu Jjiggu commented Jan 17, 2026

작업 요약

  • 이벤트 리스너 비동기로 분리하여 장애 전파 방지

Issue Link

#346

문제점 및 어려움

  • 이벤트 리스너 동작이 실패할 수 있음

해결 방안

  • 추후 Retry 로직 추가 예정

Reference

Summary by CodeRabbit

릴리스 노트

  • 성능 개선
    • 이벤트 처리가 비동기로 실행되도록 개선되어 애플리케이션의 응답성이 향상되었습니다.

✏️ Tip: You can customize this high-level summary in your review settings.

@Jjiggu Jjiggu self-assigned this Jan 17, 2026
@Jjiggu Jjiggu added the refactor 리팩토링 label Jan 17, 2026
@github-actions github-actions bot requested a review from HyemIin January 17, 2026 09:23
@coderabbitai
Copy link

coderabbitai bot commented Jan 17, 2026

설명

CookingCompleteListeneronCookingComplete 메서드에 @Async 어노테이션을 추가하여 비동기 실행을 활성화합니다. 메서드 서명과 에러 처리는 변경되지 않습니다.

변경사항

코호트 / 파일 변경 요약
이벤트 리스너 비동기화
nowait-domain/domain-redis/src/main/java/com/nowait/domaincoreredis/rank/listener/CookingCompleteListener.java
@Async 어노테이션 추가 및 org.springframework.scheduling.annotation.Async import 추가로 이벤트 핸들러를 비동기로 실행하도록 수정

예상 코드 리뷰 노력

🎯 1 (Trivial) | ⏱️ ~3 분

제안 리뷰어

  • HyemIin
🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목이 주요 변경사항을 명확하게 설명합니다. 이벤트 리스너를 비동기로 분리하는 리팩토링이 정확하게 요약되어 있습니다.

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

✨ Finishing touches
  • 📝 Generate docstrings

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.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
nowait-domain/domain-redis/src/main/java/com/nowait/domaincoreredis/rank/listener/CookingCompleteListener.java (2)

18-22: @EnableAsync가 누락되어 @Async 애너테이션이 무시됨 - 긴급 수정 필요

현재 프로젝트에 @EnableAsync 애너테이션이 존재하지 않습니다. 이로 인해 18번 라인의 @Async는 완전히 무시되며, onCookingComplete() 메서드는 동기적으로 실행됩니다.

이는 다음 문제들을 야기합니다:

  • 비동기로 의도된 코드가 실제로는 동기 실행되어 트랜잭션 완료 시점을 지연
  • AFTER_COMMIT 이벤트 리스너가 트랜잭션 완료를 차단할 수 있음
  • 데이터베이스 쓰기 작업이 이벤트 리스너 내에서 동기 실행됨

필수 조치:

  1. 애플리케이션 메인 클래스에 @EnableAsync 추가
  2. MenuCounterService 호출 전용 TaskExecutor 생성 및 @Async("menuCounterExecutor") 명시
  3. 비동기 메서드에 예외 처리 및 로깅 추가
🔧 필수 변경사항

ApiUserApplication.java / ApiAdminApplication.java에 추가:

`@EnableAsync`
`@SpringBootApplication`
public class ApiUserApplication {
    // ...
}

AsyncConfig.java에 추가:

`@Bean`(name = "menuCounterExecutor")
public Executor menuCounterExecutor() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    executor.setCorePoolSize(3);
    executor.setMaxPoolSize(5);
    executor.setQueueCapacity(50);
    executor.setThreadNamePrefix("MenuCounter-");
    executor.initialize();
    return executor;
}

CookingCompleteListener.java 변경:

-	`@Async`
+	`@Async`("menuCounterExecutor")
 	`@TransactionalEventListener`(
 		classes = CookingCompleteEvent.class,
 		phase = TransactionPhase.AFTER_COMMIT
 	)
-	public void onCookingComplete(CookingCompleteEvent event) {
-		Long storeId = event.getStoreId();
-		for (CookingCompleteEvent.Item item : event.getItems()) {
-			menuCounterService.incrementMenuCounter(
-				item.getMenuId(),
-				storeId,
-				item.getQuantity()
-			);
-		}
-	}
+	public void onCookingComplete(CookingCompleteEvent event) {
+		try {
+			Long storeId = event.getStoreId();
+			for (CookingCompleteEvent.Item item : event.getItems()) {
+				menuCounterService.incrementMenuCounter(
+					item.getMenuId(),
+					storeId,
+					item.getQuantity()
+				);
+			}
+		} catch (Exception e) {
+			// Log error - async void methods swallow exceptions silently
+			throw e;
+		}
+	}

23-31: @async 메서드의 예외 처리 누락으로 인한 조용한 장애 가능성

@Async + void 리턴 메서드의 예외는 호출부로 전파되지 않습니다. 현재 코드베이스에는 @EnableAsync가 전역으로 활성화되지 않았으며, AsyncUncaughtExceptionHandler 설정도 없어 예외가 로깅 없이 묻힐 수 있습니다. 최소한 로깅 처리가 필수적입니다.

📋 예외 로깅 추가 예시
+import lombok.extern.slf4j.Slf4j;
 
 `@Component`
 `@RequiredArgsConstructor`
+@Slf4j
 public class CookingCompleteListener {
 	private final MenuCounterService menuCounterService;
 
 	`@Async`
 	`@TransactionalEventListener`(
 		classes = CookingCompleteEvent.class,
 		phase = TransactionPhase.AFTER_COMMIT
 	)
 	public void onCookingComplete(CookingCompleteEvent event) {
-		Long storeId = event.getStoreId();
-		for (CookingCompleteEvent.Item item : event.getItems()) {
-			menuCounterService.incrementMenuCounter(
-				item.getMenuId(),
-				storeId,
-				item.getQuantity()
-			);
-		}
+		try {
+			Long storeId = event.getStoreId();
+			for (CookingCompleteEvent.Item item : event.getItems()) {
+				menuCounterService.incrementMenuCounter(
+					item.getMenuId(),
+					storeId,
+					item.getQuantity()
+				);
+			}
+		} catch (Exception ex) {
+			log.error("CookingCompleteEvent 처리 실패: storeId={}", event.getStoreId(), ex);
+			throw ex;
+		}
 	}

@Jjiggu Jjiggu merged commit 36e895d into develop Jan 17, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

refactor 리팩토링

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants