Eine Einführung in Spring Cloud Task

1. Übersicht

Das Ziel von Spring Cloud Task ist es, die Funktionalität zum Erstellen kurzlebiger Microservices für Spring Boot-Anwendungen bereitzustellen .

In Spring Cloud Task haben wir die Flexibilität, jede Aufgabe dynamisch auszuführen, Ressourcen bei Bedarf zuzuweisen und die Ergebnisse nach Abschluss der Aufgabe abzurufen.

Aufgaben ist ein neues Grundelement in Spring Cloud Data Flow, mit dem Benutzer praktisch jede Spring Boot-Anwendung als kurzlebige Aufgabe ausführen können .

2. Entwickeln einer einfachen Aufgabenanwendung

2.1. Relevante Abhängigkeiten hinzufügen

Zu Beginn können wir einen Abschnitt zum Abhängigkeitsmanagement mit Spring-Cloud-Task-Abhängigkeiten hinzufügen :

   org.springframework.cloud spring-cloud-task-dependencies 2.2.3.RELEASE pom import   

Dieses Abhängigkeitsmanagement verwaltet Versionen von Abhängigkeiten über den Importbereich.

Wir müssen die folgenden Abhängigkeiten hinzufügen:

 org.springframework.cloud spring-cloud-starter-task   org.springframework.cloud spring-cloud-task-core 

Dies ist die Verbindung zum Maven Central des Spring-Cloud-Task-Core .

Um unsere Spring Boot-Anwendung zu starten, benötigen wir nun einen Spring-Boot-Starter mit dem entsprechenden übergeordneten Element.

Wir werden Spring Data JPA als ORM-Tool verwenden, daher müssen wir auch die Abhängigkeit dafür hinzufügen:

 org.springframework.boot spring-boot-starter-data-jpa 2.2.6.RELEASE 

Die Details zum Bootstrapping einer einfachen Spring Boot-Anwendung mit Spring Data JPA finden Sie hier.

Wir können überprüfen , die neueste Version der Feder-boot-Starter-Eltern - o n Maven Central.

2.2. Die Annotation @EnableTask

Um die Funktionalität von Spring Cloud Task zu booten , müssen Sie die Annotation @EnableTask hinzufügen :

@SpringBootApplication @EnableTask public class TaskDemo { // ... } 

Die Annotation bringt die SimpleTaskConfiguration- Klasse in das Bild, die wiederum das TaskRepository und seine Infrastruktur registriert . Standardmäßig wird eine speicherinterne Zuordnung verwendet, um den Status des TaskRepository zu speichern .

Die primären Informationen von TaskRepository werden in der TaskExecution- Klasse modelliert . Die angegebenen Felder dieser Klasse sind taskName , startTime , endTime , exitMessage . Die exitMessage speichert die verfügbaren Informationen zum Exit-Zeitpunkt.

Wenn ein Exit in einem Ereignis der Anwendung durch einen Fehler verursacht wird, wird hier die vollständige Ablaufverfolgung des Ausnahmestapels gespeichert.

Spring Boot bietet eine Schnittstelle ExitCodeExceptionMapper, die nicht erfasste Ausnahmen Exit-Codes zuordnet, die ein genaues Debuggen ermöglichen . Die Cloud-Task speichert die Informationen in der Datenquelle für zukünftige Analysen.

2.3. Konfigurieren einer DataSource für TaskRepository

Die speicherinterne Zuordnung zum Speichern des TaskRepository verschwindet nach Beendigung der Task und wir verlieren Daten im Zusammenhang mit Taskereignissen . Zum Speichern in einem permanenten Speicher verwenden wir MySQL als Datenquelle mit Spring Data JPA.

Die Datenquelle wird in der Datei application.yml konfiguriert . Um Spring Cloud Task so zu konfigurieren, dass die bereitgestellte Datenquelle als Speicher für TaskRepository verwendet wird , müssen Sie eine Klasse erstellen, die DefaultTaskConfigurer erweitert .

Jetzt können wir die konfigurierte Datenquelle als Konstruktorargument an den Konstruktor der Oberklasse senden :

@Autowired private DataSource dataSource; public class HelloWorldTaskConfigurer extends DefaultTaskConfigurer{ public HelloWorldTaskConfigurer(DataSource dataSource){ super(dataSource); } }

Um die obige Konfiguration in Aktion haben, müssen wir eine Instanz mit Anmerkungen versehen Datasource mit @Autowired Annotation und injizieren die Instanz als Konstruktor-Argument einer HelloWorldTaskConfigurer Bohne oben definiert ist:

@Bean public HelloWorldTaskConfigurer getTaskConfigurer() { return new HelloWorldTaskConfigurer(dataSource); }

Damit ist die Konfiguration zum Speichern von TaskRepository in der MySQL-Datenbank abgeschlossen.

2.4. Implementierung

In Spring Boot, we can execute any Task just before application finishes its startup. We can use ApplicationRunner or CommandLineRunner interfaces to create a simple Task.

We need to implement the run method of these interfaces and declare the implementing class as a bean:

@Component public static class HelloWorldApplicationRunner implements ApplicationRunner { @Override public void run(ApplicationArguments arg0) throws Exception { System.out.println("Hello World from Spring Cloud Task!"); } }

Now, if we run our application, we should get our task producing necessary output with required tables created in our MySQL database logging the event data of the Task.

3. Life-cycle of a Spring Cloud Task

In the beginning, we create an entry in the TaskRepository. This's the indication that all beans are ready to be used in the Application and the run method of Runner interface is ready to be executed.

Upon completion of the execution of the run method or in any failure of ApplicationContext event, TaskRepository will be updated with another entry.

During the task life-cycle, we can register listeners available from TaskExecutionListener interface. We need a class implementing the interface having three methods – onTaskEnd, onTaksFailed and onTaskStartup triggered in respective events of the Task.

We need to declare the bean of the implementing class in our TaskDemo class:

@Bean public TaskListener taskListener() { return new TaskListener(); }

4. Integration With Spring Batch

We can execute Spring Batch Job as a Task and log events of the Job execution using Spring Cloud Task. To enable this feature we need to add Batch dependencies pertaining to Boot and Cloud:

 org.springframework.boot spring-boot-starter-batch   org.springframework.cloud spring-cloud-task-batch 

Here is the link to the Maven Central of spring-cloud-task-batch.

To configure a job as a Task we need to have the Job bean registered in the JobConfiguration class:

@Bean public Job job2() { return jobBuilderFactory.get("job2") .start(stepBuilderFactory.get("job2step1") .tasklet(new Tasklet(){ @Override public RepeatStatus execute( StepContribution contribution, ChunkContext chunkContext) throws Exception { System.out.println("This job is from Baeldung"); return RepeatStatus.FINISHED; } }).build()).build(); }

We need to decorate the TaskDemo class with @EnableBatchProcessing annotation:

//..Other Annotation.. @EnableBatchProcessing public class TaskDemo { // ... }

The @EnableBatchProcessing annotation enables Spring Batch features with a base configuration required to set up batch jobs.

Now, if we run the application, the @EnableBatchProcessing annotation will trigger the Spring Batch Job execution and Spring Cloud Task will log the events of the executions of all batch jobs with the other Task executed in the springcloud database.

5. Launching a Task from Stream

We can trigger Tasks from Spring Cloud Stream. To serve this purpose, we have the @EnableTaskLaucnher annotation. Once, we add the annotation with Spring Boot app, a TaskSink will be available:

@SpringBootApplication @EnableTaskLauncher public class StreamTaskSinkApplication { public static void main(String[] args) { SpringApplication.run(TaskSinkApplication.class, args); } }

The TaskSink receives the message from a stream that contains a GenericMessage containing TaskLaunchRequest as a payload. Then it triggers a Task-based on co-ordinate provided in the Task launch request.

To have TaskSink functional, we require a bean configured that implements TaskLauncher interface. For testing purpose, we're mocking the implementation here:

@Bean public TaskLauncher taskLauncher() { return mock(TaskLauncher.class); }

We need to note here that the TaskLauncher interface is only available after adding the spring-cloud-deployer-local dependency:

 org.springframework.cloud spring-cloud-deployer-local 2.3.1.RELEASE 

We can test whether the Task launched by invoking input of the Sink interface:

public class StreamTaskSinkApplicationTests { @Autowired private Sink sink; // }

Jetzt erstellen wir eine Instanz von TaskLaunchRequest und senden diese als Nutzlast des GenericMessage- Objekts. Dann können wir den Eingangskanal der Senke aufrufen und das GenericMessage- Objekt im Kanal behalten .

6. Fazit

In diesem Tutorial haben wir untersucht, wie Spring Cloud Task ausgeführt wird und wie es so konfiguriert wird, dass seine Ereignisse in einer Datenbank protokolliert werden. Wir haben auch beobachtet, wie der Spring Batch-Job definiert und im TaskRepository gespeichert wird . Zuletzt haben wir erklärt, wie wir Task in Spring Cloud Stream auslösen können.

Wie immer ist der Code auf GitHub verfügbar.