반응형

오늘은 프로젝트에서 적용한 일괄등록에서 사용한 @Async를 포스팅해볼게요.

월래는 Batch를 이용하여 새벽시간에 동작을 하도록 적용을 하였는데 @Async를 이용하여 빠르게 선처리 작업을 하고 이후 Async메서드를 호출하여 비동기 방식으로 작동하도록 구현을 하였습니다.

@Configuration
@EnableScheduling
@EnableAsync
public class AsyncThreadConfiguration {

	@Bean(name = "asyncExecutor")
	public Executor asyncThreadTaskExecutor() {
		ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
		threadPoolTaskExecutor.setCorePoolSize(2); //최초생성수
		threadPoolTaskExecutor.setMaxPoolSize(4); //max생성수
		threadPoolTaskExecutor.setThreadNamePrefix("fabs-batch-pool");

		return threadPoolTaskExecutor;
	}

	public class HandlingExecutor implements AsyncTaskExecutor {
		private final AsyncTaskExecutor executor;

		public HandlingExecutor(AsyncTaskExecutor executor) {
			this.executor = executor;
		}

		@Override
		public void execute(Runnable task) {
			executor.execute(createWrappedRunnable(task));
		}

		@Override
		public void execute(Runnable task, long startTimeout) {
			executor.execute(createWrappedRunnable(task), startTimeout);
		}

		@Override
		public Future<?> submit(Runnable task) {
			return executor.submit(createWrappedRunnable(task));
		}

		@Override
		public <T> Future<T> submit(final Callable<T> task) {
			return executor.submit(createCallable(task));
		}

		private <T> Callable<T> createCallable(final Callable<T> task) {
			return () -> {
				try {
					return task.call();
				} catch (Exception ex) {
					handle(ex);
					throw ex;
				}
			};
		}

		private Runnable createWrappedRunnable(final Runnable task) {
			return () -> {
				try {
					task.run();
				} catch (Exception ex) {
					handle(ex);
				}
			};
		}

		private void handle(Exception ex) {
			log.info("Failed to execute task. : {}", ex.getMessage());
			log.error("Failed to execute task. ", ex);
		}

		public void destroy() {
			if (executor instanceof ThreadPoolTaskExecutor) {
				((ThreadPoolTaskExecutor) executor).shutdown();
			}
		}
	}

먼저 ThreadPool설정입니다. 

setCorePoolSize 최초 생성 시 사용되는 Thread 수입니다.

setMaxPoolSize 생성할 수 있는 Thread Max값입니다. 

setThreadNamePrefix ThreadPool이 여러 곳에서 사용이 되면 알아볼 수 있도록 Name을 지정합니다.

@Bean(name = "asyncExecutor") <- "asyncExecutor"이름으로 비동기 호출을 사용할 수 있습니다.

//Controller Class
@RequestMapping(value = "/excelUpload", method = RequestMethod.POST)
public ResponseEntity<HttpResponse<?>> excelUpload(MultipartHttpServletRequest req, HttpServletResponse res,
    @AuthenticationPrincipal UserAuthentication userAuthentication) throws Exception {
    
    //비동기 Method호출
    Service.add(reqFundManagement);
    
    //비동기 Method 실행이 다 완료 안되더라도 이후 코드 실행
    
}

//Service Class

@Async("asyncExecutor")
public void add(ReqFundManagement reqFundManagement) {
    // 필요한 소스구현
}

기존 방식은

1) Excel업로드

2) 대상자 추출(LIST)

3) 대상자 등록

4) 대상자 API를 이용해 데이터 가져오기

대상자가 많을수록 3->4번이 대기 시간들이 길어져서 Batch로 만들려고 고민 중에 비동기 호출 방식 확인

비동기

1) Excel업로드

2) 대상자 추출(LIST)

3) 대상자 등록

4) 대상자 API를 이용해 데이터 가져오기

호출 순서는 같은데 3->4번 실행 후 4번 응답 대기 없이 바로 3->4가 반복을 하여 3번 대상자 먼저 등록이 되고 4번은  비동기로 작동이 돼서 여러 건을 동시에 가져와서 호출 시간이 절약이 되었어요.

 

반응형

'개발 > Java' 카테고리의 다른 글

Java Excel Upload  (0) 2021.02.25
이클립스 Formatter off  (0) 2021.02.16
Java 단방향,양방향 암호화  (1) 2021.01.25
Spring RestTemplate Converter오류  (0) 2021.01.14
List 중복 제거 및 List 정렬(Collections.sort)  (1) 2021.01.04

+ Recent posts