Hansel
스프링 @Async 비동기 문제 본문
@Async 비동기
문제
1. 임시 비밀번호를 비동기로 전송하도록 설정했지만 계속 동기로 전송되었다.
2. 임시 비밀번호 전송을 비동기로 처리했지만, 예외가 발생했을 경우 동일 스레드에서 잡아 처리하지 못한다.
사진과 같이 catch를 통한 예외처리가 되지 않고 메세지 전송 실패 체크 예외가 터진다.
지금은 이메일 전송하는 로직이 임시 비밀번호 밖에 없지만 다수의 비동기 전송 메서드가 존재할 경우
어떤 메서드에서 예외가 났는지, 어떤 메일에 보내려다 실패했는지 정확히 파악하기가 어렵다.
해결
1번 문제의 경우 스프링 AOP와 관련이 있었습니다.
우선 @Async를 통한 비동기 처리를 하기 위해서는 두가지 조건을 만족해야 합니다.
1. 접근 제한자가 public 이어야 한다.
2. 동일 클래스 내에서 호출 시 비동기 처리가 불가능하다.
처음엔 MemberService에서 resetPassword 메서드를 통해 임시 비밀번호를 생성하고 그 비밀번호를 sendNewPassword에 전달하여 사용자에게 전송하도록 구현했습니다.
현재 Asnyc 메서드가 동일 클래스 내에서 호출되고 있기 때문에 2번 조건을 어겨 비동기 처리가 되지 않았습니다.
동일 클래스 내에서 호출되는 경우엔 프록시 객체를 사용하는 것이 아닌 객체 인스턴스 메서드를 직접 실행하기 때문에, 스프링이 해당 메서드를 가로채서 다른 스레드에서 실행할 수 없기 때문입니다. @Transactional의 처리 방식을 생각하면 쉽게 이해됩니다.
결국 메일 전송을 담당하는 로직은 MailService로 분리해 처리하도록 변경했습니다.
2번 문제의 경우 다른 스레드에서 예외가 발생했기 때문에 처리하지 못하는 것으로 보였습니다.
https://www.baeldung.com/spring-async
How To Do @Async in Spring | Baeldung
How to enable and use @Async in Spring - from the very simple config and basic usage to the more complex executors and exception handling strategies.
www.baeldung.com
위 링크에 따르면,
**But if the return type is void, exceptions will not be propagated to the calling thread. So, we need to add extra configurations to handle exceptions.**
return 타입이 void인 경우 예외가 해당 메서드를 호출한 스레드로 전파되지 않기 때문에 따로 예외 처리를 해줘야 한다고 합니다.
**AsyncConfiguererSupport -> AsyncConfig**
AsyncConfiguererSupport를 상속받아 비동기 메서드 관리와 void 타입 메서드의 예외를 처리하는 Handler를 등록할 수 있습니다.
handleUncaughtException() 메서드는 비동기 메서드로부터 발생하는 예외를 처리합니다.
이메일 전송 프로토콜을 smt로 작성하여 고의로 예외를 발생시켰습니다.
예외를 처리하는 부분은 미흡하지만 의도한 대로 로그가 잘 출력되는 것을 확인할 수 있습니다.
'Spring > 이것저것' 카테고리의 다른 글
정규표현식 (0) | 2022.10.06 |
---|---|
연관관계와 쿼리처리 (0) | 2022.03.29 |