Async Execution Graceful Shutdown 설정 - YJGwon/connectruck GitHub Wiki

비동기 작업을 처리하던 중 application이 종료되면 어떻게 될까? 별도의 설정을 하지 않았다면 해당 작업은 강제 종료된다.

Test를 통해 알아보는 강제 종료 상황

테스트를 위해 비동기 작업을 수행하는 Bean을 아래와 같이 작성했다.

@Component
public class AsyncExecutor {

    private Logger log = LoggerFactory.getLogger(AsyncExecutor.class);

    @Async
    public void someJob() throws InterruptedException {
        log.info("execution start");
        Thread.sleep(5000);
        log.info("execution end");
    }
}

그 후 test로 해당 작업을 실행해보았다.

@SpringBootTest
@Import(AsyncExecutor.class)
public class AsyncThreadPoolTest {

    @Autowired
    private AsyncExecutor executor;

    @DisplayName("스프링이 종료될 때 thread pool에 남은 작업이 정상적으로 완료된 후 종료된다.")
    @Test
    void gracefullyShutdown_ifSpringContextShutDown() throws InterruptedException {
        executor.someJob();
    }
}

아래와 같이 task가 강제로 종료된다.

image

spring.task.execution.shutdown.await-termination

executor가 shutdown될 때 task가 완료될 때 까지 기다리라고 지시하는 설정

  • default: false → shutdown시 task가 강제종료

그러나…

이 값을 true로 주고 다시 위의 test를 실행하면

image

exception은 없는데, task가 종료되었다는 log는 찾아볼 수 없다. 정말 정상적으로 실행된 후 종료된 게 맞을까?

Spring Container는 기다려주지 않는다

Spring 공식 API 문서에서 executor를 설정하는 ExecutorConfigurationSupportsetWaitForTasksToCompleteOnShutdown(boolean)를 찾아보면 이렇게 적혀있다.

Note that Spring's container shutdown continues while ongoing tasks are being completed.

이 값을 true로 설정해도 spring container의 종료는 계속된다.

위 테스트의 task는 Executor말고 다른 container의 resource를 사용하지 않으니 실행을 잘 마쳤을 것이다. 그러나 Spring container resource를 사용하는 task라면 container shutdown의 영향으로 정상 종료되지 않을 가능성이 높다.

If you want this executor to block and wait for the termination of tasks before the rest of the container continues to shut down - e.g. in order to keep up other resources that your tasks may need -, set the "awaitTerminationSeconds" property instead of or in addition to this property.

Container의 shut down까지 block하고 싶다면 awaitTerminationSeconds를 설정해야 한다.

spring.task.execution.shutdown.await-termination-period

executor가 task의 완료를 기다릴 최대 시간

ExecutorConfigurationSupport.setAwaitTerminationSeconds(int)의 설명을 보면

Set the maximum number of seconds that this executor is supposed to block on shutdown in order to wait for remaining tasks to complete their execution before the rest of the container continues to shut down. This is particularly useful if your remaining tasks are likely to need access to other resources that are also managed by the container.

이 값을 통해 설정한 시간 만큼 container의 shutdown을 block할 수 있게 된다!

해당 값을 10s로 설정한 뒤 다시 test를 실행해보자.

image

비동기 작업을 마친 후 application이 종료되는 것을 확인할 수 있다.

reference