Вступление
В настоящее время вокруг нас развиваются микросервисы. Многие из этих услуг недолговечны . Запланированные задачи, синхронизация данных, агрегирование данных, создание отчетов и аналогичные услуги недолговечны. Обычно ожидается, что они начнутся, продолжатся и завершатся.
Для достижения этой цели было создано множество внешних приложений и планировщиков, однако иногда вам требуется специальная задача, которая требует глубокой интеграции с приложением вашей организации.
Платформа Spring Boot делает эту функциональность доступной для разработчиков через Spring Cloud Task API .
Что такое Spring Cloud Task?
Обычно ожидается, что службы работают долго. Средняя служба Spring Boot
включает встроенный веб-сервер, такой как Tomcat, Jetty или Undertow.
Служба завершена, потому что она остановлена намеренно или произошла
ошибка времени выполнения, например OOM ( OutOfMemoryError
).
Spring Boot был построен таким образом, но по мере смены парадигм и популярности микросервисной архитектуры многие сервисы стали недолговечными. Это было излишним, поскольку служба краткосрочных уведомлений не нуждается во встроенном сервере и может быть намного более легкой.
Spring Cloud Task - это ответ Spring на проблему недолговечных микросервисов в Spring Boot.
С Spring Cloud Task вы получаете процесс JVM по запросу, который выполняет задачу и немедленно завершается.
В этой статье мы будем много ссылаться на официальный проект Spring Cloud Task, доступный наGithub .
Техническая архитектура Spring Cloud Task
Spring Cloud Task использует несколько аннотаций для настройки системы и базы данных (по крайней мере, для производства) для записи результата каждого вызова.
Чтобы сделать приложение Spring Boot облачной задачей, вам необходимо
аннотировать один из классов конфигурации вашего приложения с помощью
@EnableTask
.
Эта аннотация импортирует
TaskLifecycleConfiguration
в ваш проект. Класс TaskLifecycleConfiguration
- это класс
конфигурации для TaskLifecycleListener
, TaskRepository
и других
полезных классов, необходимых для реализации всех функций Spring Cloud
Task.
Выполнение
Spring Initializr
Хороший способ начальной загрузки вашего скелетного проекта Spring Boot
- использовать Spring Initializr . Выберите предпочитаемую зависимость базы данных, зависимость Spring Cloud Task и зависимость Spring Data JPA:
{.ezlazyload}
Если у вас уже запущен проект с использованием Maven, добавьте соответствующие зависимости:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-task</artifactId>
<version>${version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>${version}</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>${version}</version>
</dependency>
Зависимость spring-cloud-starter-task
spring-boot-starter
,
spring-cloud-task-core
, spring-cloud-task-batch
и
spring-cloud-task-stream
.
spring-cloud-task-core
является основной, которую мы будем
использовать - вы можете импортировать spring-boot-starter
и бывшую
зависимость отдельно.
В качестве альтернативы, если вы используете Gradle:
compile group: 'org.springframework.cloud', name: 'spring-cloud-starter-task', version: '2.2.3.RELEASE'
Настройка приложения
Чтобы зарегистрировать приложение как Spring Cloud Task, вы должны
аннотировать один из классов конфигурации с помощью
@EnableTask
:
@EnableTask
@SpringBootApplication
public class SampleSpringCloudTaskApplication {
public static void main(String[] args) {
SpringApplication.run(SampleSpringCloudTaskApplication.class, args);
}
}
Поскольку @SpringBootApplication
представляет собой комбинацию
@EnableAutoConfiguration
, @Configuration
и @ComponentScan
,
вполне нормально аннотировать основной класс аннотацией @EnableTask
TaskRepository
Задачу можно создать без базы данных. В этом случае он использует находящийся в памяти экземпляр H2 для управления событиями репозитория задач. Это хорошо для разработки, но не для производства. Для производства рекомендуется источник данных. Он сохраняет все записи о выполнении ваших задач и ошибках.
Все события задачи сохраняются с помощью
TaskRepository
.
В проекте с одним источником данных Spring Cloud Task создает таблицы задач в указанной базе данных.
Однако в проекте с несколькими источниками данных вам необходимо выбрать источник данных для использования с Spring Cloud Task. Пример проекта с несколькими источниками данных можно найти в примерах проектов Spring Cloud Task .
В этом примере в классе
DataSoureConfiguration
@Configuration
public class DataSourceConfiguration {
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.HSQL)
.build();
}
@Bean
public DataSource secondDataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.build();
}
}
Чтобы указать источник данных, который будет использоваться Spring Cloud
Task, создается компонент
CustomTaskConfigurer
Он extends DefaultTaskConfigurer
, передавая квалифицированный
источник данных в конструктор:
@Component
public class CustomTaskConfigurer extends DefaultTaskConfigurer {
@Autowired
public CustomTaskConfigurer(@Qualifier("secondDataSource") DataSource dataSource) {
super(dataSource);
}
}
Если обычай TaskRepository
не определен путем расширения
SimpleTaskRepository
, то
SimpleTaskRepository
по умолчанию TaskRepository
используется Spring Cloud Task.
TaskConfigurer
TaskConfigurer
используется для настройки конфигураций Spring Cloud
Task. DefaultTaskConfigurer
- это конфигуратор по умолчанию,
используемый, если не предоставляется настраиваемый конфигуратор задач,
реализующий интерфейс TaskConfigurer
DefaultTaskConfigurer
предоставляет компоненты на основе карты, если источник данных
недоступен, и компоненты JDBC, если источник данных предоставлен.
TaskExplorer
TaskExplorer
, как следует из названия, является проводником для
выполнения задач. Это полезно для сбора актуальной информации о задачах
из репозитория задач.
По умолчанию Spring Cloud Tasks использует
SimpleTaskExplorer
.
Из TaskExplorer
вы можете запросить много полезной информации о
выполнении задач, например, общее количество TaskExecutions
, текущее
выполнение TaskExecutions
, поиск всех TaskExecutions
и т. Д.
TaskExecution
- это состояние Задачи для каждого Выполнения . Вся информация,
хранящаяся в
TaskRepository
, моделируется в этом классе. Это базовая единица для каждой задачи.
Некоторая информация хранится
executionId
- уникальный идентификатор, связанный с выполнением задачи.exitcode
- записанный код выхода для задачи.taskName
- определяемое пользователем имя задачи.startTime
- время начала задачи.endTime
- отметка времени завершения задачи.
Выполнение задачи
Чтобы выполнить нашу задачу, мы должны реализовать Runner
и
предоставить его как bean-компонент в нашем классе конфигурации.
Обычно CommandLineRunner
или ApplicationRunner
реализуется:
@Component
public class SampleCommandLineRunner implements CommandLineRunner {
@Override
public void run(String...args) throws Exception {
System.out.println("Specified Task");
}
}
@Configuration
public class TaskConfiguration {
@Bean
public SampleCommandLineRunner sampleCommandLineRunner() {
return new SampleCommandLineRunner();
}
}
И с этим из main
метода мы можем вызвать SampleCommandLineRunner
:
@SpringBootApplication
public class SomeApplication {
public static void main(String[] args) {
SpringApplication.run(SampleCommandLineRunner.class, args);
}
}
TaskExecutionListener
У всех TaskExecution
есть жизненный цикл. Spring Cloud Task записывает
эти события. В начале задачи, до того, как Runner
, создается запись в
TaskRepository
которой записывается событие запуска.
Когда задача завершена или не выполнена, выдается другое событие.
TaskExecutionListener
позволяет регистрировать слушателей для прослушивания этого события на
протяжении всего жизненного цикла.
Вы можете указать любое количество слушателей для одного и того же события.
Spring предоставляет для этого два подхода - использование
TaskExecutionListener
или подход аннотации компонента метода.
Для первого вы предоставляете компонент, реализующий
TaskExecutionListener
и его три метода:
void onTaskStartup(TaskExecution taskExecution);
void onTaskEnd(TaskExecution taskExecution);
void onTaskFailed(TaskExecution taskExecution, Throwable throwable);
-
onTaskStartup()
-TaskExecution
после сохраненияTaskRepository
в TaskRepository. -
onTaskEnd()
-TaskExecution
после обновленияTaskRepository
в TaskRepository после завершения задачи. -
onTaskFailed()
- вызывается, если во время выполнения задачи возникает неперехваченное исключение.
С другой стороны, используя подход аннотации bean-компонентов метода, вы создаете компонент и предоставляете его как bean-компонент в конфигурации Spring:
@Configuration
public class AppConfigurtion {
@Bean
public AppTaskListener appTaskListener() {
return new AppTaskListener();
}
}
@Component
class AppTaskListener {
@BeforeTask
public void beforeTaskInvocation(TaskExecution taskExecution) {
System.out.println("Before task");
}
@AfterTask
public void afterTaskInvocation(TaskExecution taskExecution) {
System.out.println("After task");
}
@FailedTask
public void afterFailedTaskInvocation(TaskExecution taskExecution, Throwable throwable) {
System.out.println("Failed task");
}
}
@BeforeTask
аналогиченonTaskStartup()
.@AfterTask
аналогиченonTaskEnd()
.@FailedTask
аналогиченonTaskFailed()
.
Сообщения о выходе из задачи
Хотя вы можете указать любое количество слушателей для конкретного
события, если TaskExecutionListener
выбрасывает исключение, вся
обработка слушателей для этого обработчика событий останавливается.
Например, если запущены три onTaskStartup()
и первый
onTaskStartup()
выдает исключение, два onTaskStartup
метода
onTaskStartup не вызываются.
Однако вызываются другие обработчики событий ( onTaskEnd()
и
onTaskFailed()
) для TaskExecutionListeners
.
Когда возникают исключения, TaskExecutionListener
возвращает код
выхода и сообщение выхода. @AfterTask
метода с помощью @AfterTask
позволит нам установить сообщение о выходе:
@AfterTask
public void afterError(TaskExecution taskExecution) {
taskExecution.setExitMessage("Custom Exit Message");
}
Сообщение о выходе может быть установлено для любого из событий
слушателя, хотя будут установлены только соответствующие сообщения. Если
задача выполняется успешно, onTaskFailed()
не срабатывает. Когда
задача завершается, устанавливается сообщение от onTaskEnd()
.
Настройка облачной задачи
Многие свойства можно переопределить с помощью TaskConfigurer
, указав
пользовательские значения в файле applications.properties
или
applications.yaml
Свойства облачной задачи Spring имеют префикс spring.cloud.task
в
файле applications.properties
Некоторые из свойств, которые можно переопределить:
spring.cloud.task.tablePrefix
- это префикс таблицы для таблиц задач дляTaskRepository
. Префикс таблицы по умолчанию - «TASK_"
.spring.cloud.task.initialize-enabled=false
- используется для включения или отключения создания таблиц задач при запуске задачи. По умолчанию это правда.spring.cloud.task.executionid=yourtaskId
- используется для настройки Spring Cloud Task для использования вашего пользовательского идентификатора задачи. По умолчанию spring генерирует идентификатор выполнения задачи для каждого выполнения задачи.
Чтобы увидеть больше настраиваемых свойств, ознакомьтесь с
askProperties
.
Регистрация событий облачных задач
Обычно во время разработки полезно просматривать журналы отладки
приложения. Чтобы изменить уровень ведения журнала для задачи Spring
Cloud, добавьте это в свой файл applications.properties
logging.level.org.springframework.cloud.task=DEBUG
Заключение
В этой статье мы рассказали о Spring Cloud Task, о том, что это такое, и
о проблемах, которые она решает. Мы также рассмотрели примеры того, как
настроить его с источником данных и запустить задачу с интерфейсами
Runner
Кроме того, мы объяснили архитектуру Spring Cloud Task и все модели
предметной области, такие как TaskExecution
, TaskExecutionListener
и т. Д., Используемые для достижения всех функциональных возможностей.