Table of Contents
Spring Boot 비동기 서비스 만들기(@Async)
로그 저장 로직을 비동기로 해 놓으면, 서비스 속도 저하가 없어,
서비스 품질 향상에 도움이 된다.
@Configuration
CorePoolSize : 기본 실행 대기하는 Thread의 수
MaxPoolSize : 동시 동작하는 최대 Thread의 수
QueueCapacity : MaxPoolSize 초과 요청시 최대 수용 가능한 Queue의 수
@Configuration
@EnableAsync
public class AsyncConfig extends AsyncConfigurerSupport {
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(500);
executor.setThreadNamePrefix("mg-async-");
executor.initialize();
return executor;
}
}
@Async
@Async
애너테이션 추가만으로 비동기 서비스가 된다.
@RequiredArgsConstructor
@Service
public class LoggerService {
private final LogKakaoRestaurantInfoRepository repository;
private final LogKakaoRestaurantInfoMapper mapper = Mappers.getMapper(LogKakaoRestaurantInfoMapper.class);
@Async
@Transactional
public void saveKakaoRestaurantInfo(List<Document> documents) {
for (Document document : documents) {
try {
LogKakaoRestaurantInfo info = repository.getById(document.getId());
mapper.updateFromDto(document, info);
} catch (EntityNotFoundException ex) {
repository.save(mapper.toEntity(document));
}
}
}
}
주의사항
-
private method 사용 불가
-
self-invocation(자가 호출) 불가
같은 Class 에 존재하는 method 에 @Async Annotation을 붙여도 동기방식으로 작동한다.
-
QueueCapacity 초과 요청에 대한 비동기 method 호출시 방어 코드 작성 필요
QueueCapacity
를 모두 소진한 경우, TaskRejectedException
이 발생한다.
@AllArgsConstructor
@Controller
public Class TestController {
private TestService testService;
@GetMapping("async")
public String testAsync() {
log.info("TEST ASYNC");
try {
for(int i=0; i<50; i++) {
testService.asyncMethod(i);
} catch (TaskRejectedException e) {
// 방어코드
}
return "";
}
}