컴퓨터과학/Spring

[spring boot] Async 비동기 메소드 사용하기

waspy 2022. 7. 15. 19:32

💡 들어가며

 Spring boot 프레임워크를 이용한 rest api 서버에 FCM을 이용한 푸시알림 서비스, 이메일 인증 서비스를 구현하게 되었는데 앞서말한 2가지 기능처럼 외부 api 통신 등의 네트워크를 이용하면 꽤 긴 딜레이가 발생한다는걸 알게 되었습니다.

 

 이와같은 딜레이를 어떻게 제거할까 고민해보았는데요, 곰곰히 생각해보니 푸시알림이나 이메일 전송등을 호출하는 로직은 해당 api의 핵심로직이 아니고 단순 알림을 위한 기능이였으므로 일단 api호출에 대한 응답을 먼저 넘기고, 스프링이 알아서 이메일을 보내든 푸시알림을 보내든 다른기능을 하도록 할 수 없을까? 하는 생각이 들어 방법을 알아보던중 비동기로 메소드를 실행할 수 있다는것을 알게 되었고 구현해보았습니다.

 

🤔 근데 비동기가 뭐지?

비동기, Asynchronize는 말 그대로 동기화가 되어있지 않다는 뜻 입니다.

일반적인 코드에서 메서드를 호출하면 해당 메서드가 응답(return)을 할 때까지 기다리다가 그 다음 로직을 실행합니다.

프로세스가 실행되는 흐름이 한개뿐이기 때문에 흐름이 중간에 막히면 다시 흐름이 열릴때까지 더이상 앞으로 나아가지 못한다고 이해할 수 있습니다.

 

하지만 비동기 메서드를 실행하게 되면, 메서드가 응답을 보낼 때 까지 기다리지 않고 바로 다음 로직을 실행하며 메서드는 별도 쓰레드로 실행됩니다.

중간에 비동기 메서드가 실행되는 순간 메인 흐름과 비동기 메서드 흐름 2개로 분리되어 각자가 따로 실행된다고 생각하면 됩니다.

 

Spring에서는 @Async 라는 어노테이션을 제공하며 이를 이용하여 FCM 서비스를 호출하는 로직을 기다리지 않고 다른 쓰레드로 분리하여 실행하고 클라이언트 에게는 api 요청에 대한 응답을 먼저 보내는 작업을 해보겠습니다.

 

💻 @Async 설정하기

우선 스프링에서 @Async 어노테이션을 사용하기 위해선 비동기 작업에 대한 설정을 해야합니다.

AsyncConfig class를 생성하여 다음 메서드를 오버라이드 해줍니다.

@Configuration
@EnableAsync
public class AsyncConfig extends AsyncConfigurerSupport {
    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(2);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(500);
        executor.setThreadNamePrefix("async-");
        executor.initialize();

        return executor;
    }
}

 

@Configuration: 설정 클래스를 스프링 빈으로 등록하기 위한 어노테이션 입니다.

@EnableAsync: 스프링 프레임워크가 Async 어노테이션을 감지하고 비동기로 실행할 수 있도록 하는 설정입니다.

 

getAsyncExecutor() 메서드를 오버라이드 하여 새로운 쓰레드 풀 생성객체 executor을 생성하고 초기화 해줍니다.

쓰레드 풀을 미리 만들어두어 @Async 어노테이션이 걸려있는 메소드를 실행할 때 생성되어있는 쓰레드에서 실행될 수 있도록 합니다.

 

corePoolSize: 는 최소 쓰레드의 개수 입니다.

maxPoolSize: 최대 쓰레드의 개수 입니다.

QueueCapacity: 큐의 크기로, 대기중인 비동기 메소드들의 수가 여기서 정한 큐의 크기를 벗어나면 쓰레드의 개수를 최대 쓰레드 개수까지 증가시킵니다.

ThreadNamePrefix: 말그대로 쓰레드 이름의 앞에 고정적으로 붙일 이름을 의미합니다.

 

🥹 적용하기

위와같은 설정을 한 뒤 

@Async
@Transactional
public void sendItemActivatedNotice(Long itemIdx) {...}

 위와 같이 비동기로 동작을 원하는 서비스의 메서드에 @Async 어노테이션을 추가합니다.

앞서 정한 Async Config에 맞춰 비동기 메소드들이 관리되고 실행됩니다.

 

⚠️ 주의할점

비동기로 구현할 메서드는 실행 결과 여부가 응답에 영향을 주지 않는 로직만 포함해야 합니다.

예를들어 새로운 게시물을 생성하고 성공한다면 201을 리턴해야한다고 할 때, 성공적으로 생성된 것을 확인하고 201를 클라이언트에게 응답해야합니다. 만약 이 메서드를 비동기로 등록한다면, 게시물 등록 중 오류가 발생하더라도 이미 201를 리턴해 버린 상태가 되어 문제가 생기겠죠?

비동기 메서드는 충분히 검토가 이루어진 후 적용되어야 할 것 같습니다.

반응형