Рубрики
Без рубрики

Изящное завершение работы приложения Spring Boot

Изящно завершите работу приложения Spring Boot.

Автор оригинала: baeldung.

1. Обзор

При завершении работы по умолчанию Spring TaskExecutor просто прерывает все запущенные задачи, но вместо этого может быть неплохо дождаться завершения всех запущенных задач. Это дает возможность каждой задаче принять меры для обеспечения безопасного завершения работы.

В этом кратком руководстве мы узнаем, как сделать это более изящное завершение работы приложения Spring Boot, когда оно включает в себя задачи, выполняемые с использованием пулов потоков.

2. Простой Пример

Давайте рассмотрим простое приложение Spring Boot. Мы автоматически подключим по умолчанию TaskExecutor bean:

@Autowired
private TaskExecutor taskExecutor;

При запуске приложения давайте выполним 1-минутный процесс с использованием потока из пула потоков:

taskExecutor.execute(() -> {
    Thread.sleep(60_000);
});

Когда инициируется завершение работы, например, через 20 секунд после запуска, поток в этом примере прерывается, и приложение немедленно завершает работу.

3. Дождитесь завершения заданий

Давайте изменим поведение по умолчанию task executor, создав пользовательский ThreadPoolTaskExecutor bean.

Этот класс предоставляет флаг setWaitForTasksToCompleteOnShutdown для предотвращения прерывания выполнения задач. Давайте установим его в true :

@Bean
public TaskExecutor taskExecutor() {
    ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
    taskExecutor.setCorePoolSize(2);
    taskExecutor.setMaxPoolSize(2);
    taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
    taskExecutor.initialize();
    return taskExecutor;
}

И мы перепишем более раннюю логику, чтобы создать 3 потока, каждый из которых выполняет задачу длиной в 1 минуту.

@PostConstruct
public void runTaskOnStartup() {
    for (int i = 0; i < 3; i++) {
        taskExecutor.execute(() -> {
            Thread.sleep(60_000);
        });
    }
}

Теперь давайте инициируем выключение в течение первых 60 секунд после запуска.

Мы видим, что приложение выключается только через 120 секунд после запуска. Размер пула 2 позволяет выполнять только две одновременные задачи, поэтому третья стоит в очереди.

Установка флага гарантирует, что как текущие выполняемые задачи, так и задачи, поставленные в очередь, будут завершены .

Обратите внимание, что при получении запроса на завершение работы исполнитель task закрывает очередь , чтобы новые задачи не могли быть добавлены.

4. Максимальное Время Ожидания Перед Завершением

Хотя мы настроили ожидание завершения текущих и стоящих в очереди задач, Spring продолжает выключать остальную часть контейнера . Это может высвободить ресурсы, необходимые нашему исполнителю задач, и привести к сбою задач.

Чтобы заблокировать завершение работы остальной части контейнера, мы можем указать максимальное время ожидания на ThreadPoolTaskExecutor:

taskExecutor.setAwaitTerminationSeconds(30);

Это гарантирует, что в течение указанного периода времени процесс завершения работы на уровне контейнера будет заблокирован .

Когда мы устанавливаем флаг setWaitForTasksToCompleteOnShutdown в true , нам нужно указать значительно более высокий тайм-аут, чтобы все остальные задачи в очереди также выполнялись.

5. Заключение

В этом кратком руководстве мы увидели, как безопасно завершить работу приложения Spring Boot, настроив компонент task executor для выполнения запущенных и отправленных задач до конца. Это гарантирует, что все задачи будут иметь указанное количество времени для завершения своей работы.

Один очевидный побочный эффект заключается в том, что он также может привести к более длительной фазе выключения . Поэтому нам нужно решить, использовать его или нет, в зависимости от характера приложения.

Как всегда, примеры из этой статьи доступны на GitHub .