Skip to content
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

refactor: 비동기 + 이벤트 리스닝 방식으로 알림 로직 개선 #906

Open
wants to merge 25 commits into
base: develop
Choose a base branch
from

Conversation

coli-geonwoo
Copy link
Contributor

@coli-geonwoo coli-geonwoo commented Nov 14, 2024

🚩 연관 이슈

close #905


📝 작업 내용


🏞️ 스크린샷 (선택)

image


🗣️ 리뷰 요구사항 (선택)

관련 설명은 노션 페이지에서 볼 수 있습니다. 리팩터링 양이 꽤 되어서 꼭 참고해주세요!

Approve&Merge되지 않아도 괜찮아요. 합리적이라 생각하는지에 대한 의견도 이야기해주시면 좋을 것 같아요.

Copy link

Test Results

 55 files  +2   55 suites  +2   8s ⏱️ +2s
196 tests +8  196 ✅ +8  0 💤 ±0  0 ❌ ±0 
197 runs  +8  197 ✅ +8  0 💤 ±0  0 ❌ ±0 

Results for commit eb4f49a. ± Comparison against base commit a7ba2fd.

This pull request removes 9 and adds 17 tests. Note that renamed tests count towards both.
com.ody.auth.JwtTokenProviderTest$validateAccessToken ‑ [1] accessToken=com.ody.auth.token.AccessToken@5fd7e75d
com.ody.auth.JwtTokenProviderTest$validateAccessToken ‑ [2] accessToken=com.ody.auth.token.AccessToken@80ea360
com.ody.common.validator.FutureOrPresentDateTimeValidatorTest ‑ [1] date=2024-11-14, time=19:17:29.656179467, expected=false
com.ody.common.validator.FutureOrPresentDateTimeValidatorTest ‑ [2] date=2024-11-14, time=20:17:29.656214011, expected=true
com.ody.common.validator.FutureOrPresentDateTimeValidatorTest ‑ [3] date=2024-11-14, time=18:17:29.656200556, expected=false
com.ody.common.validator.FutureOrPresentDateTimeValidatorTest ‑ [4] date=2024-11-15, time=19:17:29.656179467, expected=true
com.ody.notification.service.FcmPushSenderTest ‑ 출발 알림이 DISMISSED 상태가 아니면 이면 푸시 알림을 보내고, DONE 상태로 변경한다.
com.ody.notification.service.NotificationServiceTest ‑ 모임방에 대한 구독을 취소한다
com.ody.notification.service.NotificationServiceTest ‑ 재촉하기 메시지가 발송된다
com.ody.auth.JwtTokenProviderTest$validateAccessToken ‑ [1] accessToken=com.ody.auth.token.AccessToken@d49a04a
com.ody.auth.JwtTokenProviderTest$validateAccessToken ‑ [2] accessToken=com.ody.auth.token.AccessToken@15b35d3a
com.ody.common.exception.AsyncExceptionHandlerTest ‑ 비동기 메서드에서 발생한 에러를 핸들링한다
com.ody.common.validator.FutureOrPresentDateTimeValidatorTest ‑ [1] date=2024-11-15, time=04:59:22.970618409, expected=false
com.ody.common.validator.FutureOrPresentDateTimeValidatorTest ‑ [2] date=2024-11-15, time=05:59:22.970637445, expected=true
com.ody.common.validator.FutureOrPresentDateTimeValidatorTest ‑ [3] date=2024-11-15, time=03:59:22.970627406, expected=false
com.ody.common.validator.FutureOrPresentDateTimeValidatorTest ‑ [4] date=2024-11-16, time=04:59:22.970618409, expected=true
com.ody.mate.controller.MateControllerTest ‑ 바로 전송해야 하는 입장/출발 알림의 경우, 트랜잭션이 완료 된 후 알림을 조회한다
com.ody.notification.service.FcmEventListenerTest ‑ NoticeEvent 발생 시, 공지 알림 발송 로직을 실행한다
com.ody.notification.service.FcmEventListenerTest ‑ NudgeEvent 발생 시, 넛지 알림 발송 로직을 실행한다
…

Copy link

📝 Test Coverage Report

Overall Project 81.52% -0.49% 🍏
Files changed 91.08% 🍏

File Coverage
SubscribeEvent.java 100% 🍏
PushEvent.java 100% 🍏
UnSubscribeEvent.java 100% 🍏
AsyncConfig.java 100% 🍏
AsyncExceptionHandler.java 100% 🍏
FcmEventPublisher.java 100% 🍏
NotificationService.java 98.85% 🍏
MateService.java 94.93% 🍏
MeetingService.java 93.33% 🍏
NoticeEvent.java 70% -30%
FcmEventListener.java 66.67% -33.33%
NudgeEvent.java 62.5% -37.5%
FcmPushSender.java 60.78% 🍏

@eun-byeol eun-byeol changed the title refactor : 비동기 + 이벤트 리스닝 방식으로 알림 로직 개선 refactor: 비동기 + 이벤트 리스닝 방식으로 알림 로직 개선 Nov 15, 2024
Copy link
Contributor

@hyeon0208 hyeon0208 left a comment

Choose a reason for hiding this comment

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

�전반적으로 깔끔하게 코드를 개선한 것 같아요 👍
알림 전송에 대해서 비동기 처리가 필요했었는데 개선해주셨네요 😄
코드 리뷰하면서 이벤트 리스너를 꼭 사용해야하는지가 궁금했던 것 같아요
관련해서 질문들 남겼습니다 !

executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); //스레드풀이 가득찼을 경우 톰캣 스레드에서 처리
int coreCount = Runtime.getRuntime().availableProcessors();
executor.setCorePoolSize(coreCount);
executor.setThreadNamePrefix("ody-fcm");
Copy link
Contributor

Choose a reason for hiding this comment

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

[제안]
지금 대로면 fcm 관련 로직이 아닌 곳에서 @Asnyc를 사용할 경우데 해당 스레드가 ody-fcm으로 표시되서
혼란이 발생할 수 있을 것 같아요

해당 Executor의 Bean 이름을 fcm으로 네이밍해주고 fcm 관련 비동기 처리는 해당 Bean을 사용하게 하면 어떨까요 ?

@EnableAsync
@Configuration
@RequiredArgsConstructor
public class AsyncConfig implements AsyncConfigurer {
Copy link
Contributor

Choose a reason for hiding this comment

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

[질문]
AsyncConfigurer 인터페이스를 구현해 설정을 구성했는데
직접 Bean으로 등록해 등록해주는 것 보다 장점이 있을까요??

만약 비동기 처리에 대한 정책들이 각 로직마다 다르다면 (밑에 리뷰와 같은 상황에서)
다형성 Bean으로 관리하게 될 것 같아 Bean 방식이 유연하지 않을까 해서
추가적인 장점이 있는지 궁금해서 여쭙니다 😄


@Slf4j
@Component
public class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
Copy link
Contributor

Choose a reason for hiding this comment

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

오호 이렇게 비동기 처리 에러를 로깅할 수 있군요 👍

Comment on lines +136 to +137
Notification memberDeletionNotification = Notification.createMemberDeletion(mate);
notificationService.save(memberDeletionNotification);
Copy link
Contributor

Choose a reason for hiding this comment

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

메서드의 역할에 맞게 분리되었네요 👍

Comment on lines +55 to +62
@Async
@Transactional(propagation = Propagation.REQUIRES_NEW) // 추가 커밋 허용을 위해 트랜잭션을 염
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)// 커밋 이후 발송
public void sendPushMessage(PushEvent pushEvent) {
Notification notification = pushEvent.getNotification();
GroupMessage groupMessage = GroupMessage.from(notification);
fcmPushSender.sendGeneralMessage(groupMessage.message(), notification);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

[질문]
Async도 프록시 객체가 생성되고 Transactional도 프록시 객체가 생성되서
두 어노테이션을 같이 사용하면 롤백이 안되는 등의 이슈가 있는 것으로 알고 있어요

추가 커밋 허용을 위해 트랜잭션을 열었다고 했는데
sendGeneralMessage() 메서드에 트랜잭션이 선언되어 있어 문제가 없지 않을까요 ??

  • 추가 질문
    현재 알림 로직을 호출하는 메서드들은
    비즈니스로직을 처리 후에 마지막에 알림 로직을 호출하고 있는데
    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)가 필요�했던 이유가
    궁금합니다 !

}

private void sendGeneralMessage(Message message, Notification notification) {
public void sendGeneralMessage(Message message, Notification notification) {
Copy link
Contributor

Choose a reason for hiding this comment

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

[질문]
topic, divice token 메세지를 모두 일반 메세지로 표현하신 것 같은데
일반적이지 않은 메세지는 뭐라고 생각하시나요 ??

.then()
.statusCode(201);

Thread.sleep(1000L); //비동기 메서드 유휴 시간
Copy link
Contributor

Choose a reason for hiding this comment

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

[제안]
비동기 처리가 실행 환경에 따라 1초보다 더 걸릴 수 있으니
sleep으로 테스트하면 비결정적인 테스트가 될 것 같아요...

CountDownLatch를 사용해 결정적인 테스트로 수정해보면 어떨까요?

import org.springframework.context.ApplicationEvent;

@Getter
public class NoticeEvent extends ApplicationEvent {
Copy link
Contributor

Choose a reason for hiding this comment

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

Spring 프레임워크 4.2 버전 이후 부터는 ApplicationEvent를 상속받지 않아도
이벤트 객체를 생성 가능하다고 하네요!
https://www.baeldung.com/spring-events

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

refactor : FCM 관련 로직을 비동기 + 이벤트 리스닝 방식으로 변경
2 participants