카테고리 없음

Spring MVC 에서 suspend 이용하기

dev_roach 2022. 9. 22. 00:07
728x90

어떻게 하면 Spring MVC 에서 suspend 를 Controller 에 쓸 수 있을까 고민해보다가. Spring 5.3 Version 부터 코루틴 지원 한다는 Reddit 의 글을 보고 팀에서 이용하는 코틀린 버전을 2.4.5 버전으로 업그레이드 했다. 그 결과 Controller 에서 suspend 를 지원할 수 있게 되었다. 과연 어떻게 동작하는 걸까 알아보도록 하자.

Reactive Type (Mono, Flux) 의 Return 가능

일단 suspend 가 붙은 controller 메소드의 return Type 을 알맞게 Mono 또는 Flux 형태로 바꾸어준다.

Spring 내에서 Handler 의 ReturnValue 의 Type 에 따라서 알맞은 Handler 가 처리하게 되어 있다. 따라서 현재는 ReactiveTypeHandler 라는 아래의 클래스가 value 를 가공하게 된다.

결국 하단에서 DefferedResult 가 되고 DefferedResult 를 가공하는 Method 인 startDefferedResultProcessing 이 시작된다.

아래 사진과 같이 처음에는 Result 에 값이 없는 것을 확인할 수 있다.

이제 어떻게 Async 로 동작하는지 좀 더 자세하게 알아보자. 

아래 코드를 한번 보자.

startDefferedResultProcessing 의 코드를 살펴보면 위처럼 setResultHandler 메소드에 해야할 해당 작업을 처리하라고 시키는 것을 확인할 수 있다. 해당 setResultHandler 는 쉽게 얘기하면 Callback Function 을 받는 것이다.

우리는 defferedResult 의 작업이 완료되면 applyPostProcess 작업을 하고 setConcurrentResultAndDispatch 를 할거야 라는 뜻이다. 그럼 이 코드는 어디에 있을까? setResultHandler 안의 코드를 한번 보자.

여기서 작업이 완료된 뒤 우리가 지정한 Callback 함수를 호출해주게 된다.

우리가 넘겨줬던 applyPostProcess 를 먼져 실행해서 Interceptor Chain 을 모두 태운뒤,  setConcurrentResultAndDispatch 를 실행시켜서 현재 Result 를 저장하고 다시 disptach 시켜주는 것을 확인할 수 있다.

 

어떤 Thread Pool 을 사용하는 거지?

그리고 어떤 Dispatcher 를 사용하나 봤더니 Coroutine 기본 Dispatcher 를 사용하고 있음을 알 수 있다. 

요건 내가 위에서 아마 Coroutine Dispatcher 를 설정해주지 않아서 그런것 같다.

진짜 제대로 바뀌는건지 테스트 하기 위해서 위의 Controller 에서 기본말고 Dispatcher.IO 를 이용해보도록 하겠다.

컨트롤러와 Spring 내부 구현에서 이름이 다른데 요건 Kotlin 에서 Java 로 가서 그런걸로 보인다. 내가 이렇게 추측하는 이유는 Thread Local 에서 저장하는 MDC Context 를 잘 물고 갔기 때문이다. 현재 별도의 Copy 는 해주고 있지 않아서, 별도의 ThreadPool 이 아니고, Controller 단에서 선언한 ThreadPool 을 이용하고 있음을 알 수 있다.

후기

간만에 삽질을 엄청했는데 결국 위에서 사용하는 CoroutineThreadPool 을 아래에서도 사용하는게 좀 신기하긴하다..

나중에 좀 더 공부해봐야지