功能
本節將更詳細地介紹 Spring Cloud Task,包括如何使用它、如何配置它以及適當的擴充套件點。
Spring Cloud Task 的生命週期
在大多數情況下,現代雲環境是圍繞不期望結束的程序執行而設計的。如果它們確實結束了,它們通常會被重新啟動。雖然大多數平臺確實有某種方法可以執行一個在結束後不重新啟動的程序,但該執行的結果通常不會以可消費的方式維護。Spring Cloud Task 提供了在環境中執行短生命週期程序並記錄結果的能力。這樣做允許圍繞短生命週期程序以及透過訊息整合任務來實現長時間執行服務的微服務架構。
雖然此功能在雲環境中很有用,但在傳統部署模型中也可能出現同樣的問題。當使用 cron 等排程程式執行 Spring Boot 應用程式時,能夠在應用程式完成之後監視其結果會很有用。
Spring Cloud Task 採取的方法是,Spring Boot 應用程式可以有開始和結束,並且仍然成功。批處理應用程式是預期結束(並且通常是短生命週期)的程序如何提供幫助的一個示例。
Spring Cloud Task 記錄給定任務的生命週期事件。大多數長時間執行的程序(以大多數 Web 應用程式為典型)不儲存其生命週期事件。Spring Cloud Task 的核心任務則會。
生命週期由單個任務執行組成。這是配置為任務(即具有 Sprint Cloud Task 依賴項)的 Spring Boot 應用程式的物理執行。
在任務開始時,在任何 CommandLineRunner 或 ApplicationRunner 實現執行之前,會在 TaskRepository 中建立一個記錄開始事件的條目。此事件透過 Spring Framework 觸發 SmartLifecycle#start 來觸發。這表示系統所有 Bean 都已準備好使用,並且在執行 Spring Boot 提供的任何 CommandLineRunner 或 ApplicationRunner 實現之前發生。
任務的記錄僅在 ApplicationContext 成功引導時發生。如果上下文完全無法引導,則不記錄任務的執行。 |
在 Spring Boot 的所有 *Runner#run 呼叫完成後或 ApplicationContext 失敗(由 ApplicationFailedEvent 指示)時,任務執行的結果會在儲存庫中更新。
如果應用程式要求在任務完成時(所有 *Runner#run 方法已呼叫且任務儲存庫已更新)關閉 ApplicationContext,請將屬性 spring.cloud.task.closecontextEnabled 設定為 true。 |
TaskExecution
儲存在 TaskRepository 中的資訊在 TaskExecution 類中建模,幷包含以下資訊
| 欄位 | 描述 |
|---|---|
|
任務執行的唯一 ID。 |
|
從 |
|
任務的名稱,由配置的 |
|
任務開始時間,由 |
|
任務完成時間,由 |
|
退出時可用的任何資訊。這可以透過 |
|
如果異常是任務結束的原因(由 |
|
作為命令列引數傳遞給可執行引導應用程式的字串命令列引數列表。 |
對映退出程式碼
當任務完成時,它會嘗試向作業系統返回退出程式碼。如果我們檢視 原始示例,我們可以看到我們沒有控制應用程式的這個方面。因此,如果丟擲異常,JVM 會返回一個程式碼,該程式碼可能對您的除錯有用,也可能沒用。
因此,Spring Boot 提供了一個介面 ExitCodeExceptionMapper,它允許您將未捕獲的異常對映到退出程式碼。這樣做可以讓您在退出程式碼級別指示出了什麼問題。此外,透過以這種方式對映退出程式碼,Spring Cloud Task 會記錄返回的退出程式碼。
如果任務因 SIG-INT 或 SIG-TERM 終止,則除非程式碼中另有規定,否則退出程式碼為零。
| 任務執行時,退出程式碼在儲存庫中儲存為 null。任務完成後,根據本節前面所述的準則儲存相應的退出程式碼。 |
配置
Spring Cloud Task 提供了開箱即用的配置,如 DefaultTaskConfigurer 和 SimpleTaskConfiguration 類中定義。本節將介紹預設值以及如何根據您的需求自定義 Spring Cloud Task。
資料來源
Spring Cloud Task 使用資料來源來儲存任務執行的結果。預設情況下,我們提供了一個 H2 記憶體例項,以提供一種簡單的開發引導方法。但是,在生產環境中,您可能希望配置自己的 DataSource。
如果您的應用程式只使用一個 DataSource,並且該資料來源既用作您的業務模式又用作任務儲存庫,則您只需提供任何 DataSource(最簡單的方法是透過 Spring Boot 的配置約定)。此 DataSource 將由 Spring Cloud Task 自動用於儲存庫。
如果您的應用程式使用多個 DataSource,則需要使用適當的 DataSource 配置任務儲存庫。此自定義可以透過 TaskConfigurer 的實現來完成。
表字首
TaskRepository 的一個可修改屬性是任務表的表字首。預設情況下,它們都以 TASK_ 為字首。TASK_EXECUTION 和 TASK_EXECUTION_PARAMS 是兩個示例。但是,修改此字首可能有一些原因。如果需要將模式名稱新增到表名稱前面,或者在同一模式中需要多組任務表,則必須更改表字首。您可以透過將 spring.cloud.task.tablePrefix 設定為您需要的字首來完成此操作,如下所示
spring.cloud.task.tablePrefix=yourPrefix
透過使用 spring.cloud.task.tablePrefix,使用者承擔建立符合任務表模式標準但又根據使用者業務需求進行修改的任務表的責任。您可以將 Spring Cloud Task Schema DDL 作為建立您自己的任務 DDL 的指南,如此處所示。
啟用/停用表初始化
如果您正在建立任務表並且不希望 Spring Cloud Task 在任務啟動時建立它們,請將 spring.cloud.task.initialize-enabled 屬性設定為 false,如下所示
spring.cloud.task.initialize-enabled=false
它預設為 true。
屬性 spring.cloud.task.initialize.enable 已棄用。 |
外部生成任務 ID
在某些情況下,您可能希望允許任務請求時間與基礎設施實際啟動任務時間之間的差異。Spring Cloud Task 允許您在請求任務時建立 TaskExecution。然後將生成的 TaskExecution 的執行 ID 傳遞給任務,以便任務可以透過任務的生命週期更新 TaskExecution。
可以透過在引用儲存 TaskExecution 物件的資料庫的 TaskRepository 實現上呼叫 createTaskExecution 方法來建立 TaskExecution。
要將您的任務配置為使用生成的 TaskExecutionId,請新增以下屬性
spring.cloud.task.executionid=yourtaskId
外部任務 ID
Spring Cloud Task 允許您為每個 TaskExecution 儲存一個外部任務 ID。要將您的任務配置為使用生成的 TaskExecutionId,請新增以下屬性
spring.cloud.task.external-execution-id=<externalTaskId>
父任務 ID
Spring Cloud Task 允許您為每個 TaskExecution 儲存一個父任務 ID。例如,一個任務執行另一個任務或多個任務,並且您希望記錄哪個任務啟動了每個子任務。要將您的任務配置為設定父 TaskExecutionId,請在子任務上新增以下屬性
spring.cloud.task.parent-execution-id=<parentExecutionTaskId>
TaskConfigurer
TaskConfigurer 是一個策略介面,允許您自定義 Spring Cloud Task 元件的配置方式。預設情況下,我們提供了 DefaultTaskConfigurer,它提供邏輯預設值:基於 Map 的記憶體中元件(如果沒有提供 DataSource,則適用於開發)和基於 JDBC 的元件(如果 DataSource 可用,則適用)。
TaskConfigurer 允許您配置三個主要元件
| 元件 | 描述 | 預設(由 DefaultTaskConfigurer 提供) |
|---|---|---|
|
要使用的 |
|
|
要使用的 |
|
|
在執行任務更新時使用的事務管理器。 |
如果使用了 |
您可以透過建立 TaskConfigurer 介面的自定義實現來定製上表中描述的任何元件。通常,擴充套件 DefaultTaskConfigurer(如果未找到 TaskConfigurer 則提供)並重寫所需的 getter 就足夠了。但是,可能需要從頭開始實現您自己的。
除非使用者將其用於提供要作為 Spring Bean 公開的實現,否則不應直接使用 TaskConfigurer 中的 getter 方法。 |
任務執行監聽器
TaskExecutionListener 允許您註冊在任務生命週期期間發生的特定事件的監聽器。為此,請建立一個實現 TaskExecutionListener 介面的類。實現 TaskExecutionListener 介面的類將收到以下事件的通知
-
onTaskStartup:在將TaskExecution儲存到TaskRepository之前。 -
onTaskEnd:在更新TaskRepository中的TaskExecution條目並標記任務的最終狀態之前。 -
onTaskFailed:當任務丟擲未處理的異常時,在呼叫onTaskEnd方法之前。
Spring Cloud Task 還允許您使用以下方法註解將 TaskExecution 監聽器新增到 Bean 中的方法
-
@BeforeTask:在將TaskExecution儲存到TaskRepository之前。 -
@AfterTask:在更新TaskRepository中的TaskExecution條目並標記任務的最終狀態之前。 -
@FailedTask:當任務丟擲未處理的異常時,在呼叫@AfterTask方法之前。
以下示例顯示了正在使用的三個註解
public class MyBean {
@BeforeTask
public void methodA(TaskExecution taskExecution) {
}
@AfterTask
public void methodB(TaskExecution taskExecution) {
}
@FailedTask
public void methodC(TaskExecution taskExecution, Throwable throwable) {
}
}
在鏈中比 TaskLifecycleListener 存在更早地插入 ApplicationListener 可能會導致意外的影響。 |
任務執行監聽器丟擲的異常
如果 TaskExecutionListener 事件處理程式丟擲異常,則該事件處理程式的所有監聽器處理都將停止。例如,如果三個 onTaskStartup 監聽器已啟動,並且第一個 onTaskStartup 事件處理程式丟擲異常,則其他兩個 onTaskStartup 方法不會被呼叫。但是,TaskExecutionListeners 的其他事件處理程式(onTaskEnd 和 onTaskFailed)將被呼叫。
當 TaskExecutionListener 事件處理程式丟擲異常時返回的退出程式碼是 ExitCodeEvent 報告的退出程式碼。如果沒有發出 ExitCodeEvent,則評估丟擲的異常以檢視其是否為 ExitCodeGenerator 型別。如果是,則返回 ExitCodeGenerator 的退出程式碼。否則,返回 1。
如果在 onTaskStartup 方法中丟擲異常,則應用程式的退出程式碼將為 1。如果在 onTaskEnd 或 onTaskFailed 方法中丟擲異常,則應用程式的退出程式碼將是根據上述規則確定的退出程式碼。
如果 onTaskStartup、onTaskEnd 或 onTaskFailed 中丟擲異常,您不能使用 ExitCodeExceptionMapper 覆蓋應用程式的退出程式碼。 |
退出訊息
您可以使用 TaskExecutionListener 以程式設計方式設定任務的退出訊息。這透過設定 TaskExecution 的 exitMessage 來完成,然後將其傳遞給 TaskExecutionListener。以下示例顯示了一個使用 @AfterTask ExecutionListener 註解的方法
@AfterTask
public void afterMe(TaskExecution taskExecution) {
taskExecution.setExitMessage("AFTER EXIT MESSAGE");
}
可以在任何監聽器事件(onTaskStartup、onTaskFailed 和 onTaskEnd)中設定 ExitMessage。三個監聽器的優先順序順序如下
-
onTaskEnd -
onTaskFailed -
onTaskStartup
例如,如果您為 onTaskStartup 和 onTaskFailed 監聽器設定了 exitMessage,並且任務在沒有失敗的情況下結束,則 onTaskStartup 的 exitMessage 將儲存在儲存庫中。否則,如果發生故障,則儲存 onTaskFailed 的 exitMessage。此外,如果您使用 onTaskEnd 監聽器設定 exitMessage,則 onTaskEnd 的 exitMessage 將覆蓋 onTaskStartup 和 onTaskFailed 的退出訊息。
限制 Spring Cloud Task 例項
Spring Cloud Task 允許您確定給定任務名稱的只有一個任務可以同時執行。為此,您需要為每個任務執行建立任務名稱並設定 spring.cloud.task.single-instance-enabled=true。當第一個任務執行正在執行時,任何其他時候您嘗試執行具有相同任務名稱和 spring.cloud.task.single-instance-enabled=true 的任務,該任務將失敗並顯示以下錯誤訊息:Task with name "application" is already running. spring.cloud.task.single-instance-enabled 的預設值為 false。以下示例演示如何將 spring.cloud.task.single-instance-enabled 設定為 true
spring.cloud.task.single-instance-enabled=true or false
要使用此功能,您必須將以下 Spring Integration 依賴項新增到您的應用程式中
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-jdbc</artifactId>
</dependency>
| 如果任務因啟用此功能且另一個任務正在執行具有相同任務名稱而失敗,則應用程式的退出程式碼將為 1。 |
Spring AOT 和本機編譯的單例項用法
在建立原生編譯應用程式時使用 Spring Cloud Task 的單例項功能,您需要在構建時啟用該功能。為此,請新增 process-aot 執行並將 spring.cloud.task.single-step-instance-enabled=true 設定為 JVM 引數,如下所示
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<id>process-aot</id>
<goals>
<goal>process-aot</goal>
</goals>
<configuration>
<jvmArguments>
-Dspring.cloud.task.single-instance-enabled=true
</jvmArguments>
</configuration>
</execution>
</executions>
</plugin>
為 ApplicationRunner 和 CommandLineRunner 啟用觀測
要為 ApplicationRunner 或 CommandLineRunner 啟用任務觀測,請將 spring.cloud.task.observation.enabled 設定為 true。
使用 SimpleMeterRegistry 啟用觀測的示例任務應用程式可以在此處找到。
停用 Spring Cloud Task 自動配置
在某些情況下,Spring Cloud Task 不應該為某個實現自動配置,您可以停用 Task 的自動配置。這可以透過將以下註解新增到您的任務應用程式來完成
@EnableAutoConfiguration(exclude={SimpleTaskAutoConfiguration.class})
您還可以透過將 spring.cloud.task.autoconfiguration.enabled 屬性設定為 false 來停用任務自動配置。
關閉上下文
如果應用程式要求在任務完成時(所有 *Runner#run 方法已呼叫且任務儲存庫已更新)關閉 ApplicationContext,請將屬性 spring.cloud.task.closecontextEnabled 設定為 true。
另一種關閉上下文的情況是當任務執行完成但應用程式不終止時。在這些情況下,上下文保持開啟狀態,因為已分配了一個執行緒(例如:如果您正在使用 TaskExecutor)。在這些情況下,在啟動任務時將 spring.cloud.task.closecontextEnabled 屬性設定為 true。這將關閉應用程式的上下文,一旦任務完成。從而允許應用程式終止。
啟用任務指標
Spring Cloud Task 與 Micrometer 整合,併為其執行的任務建立觀測。要啟用任務可觀測性整合,您必須將 spring-boot-starter-actuator、您首選的登錄檔實現(如果您想釋出指標)和 micrometer-tracing(如果您想釋出跟蹤資料)新增到您的任務應用程式中。以下是使用 Influx 啟用任務可觀測性和指標的 Maven 依賴項示例
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-influx</artifactId>
<scope>runtime</scope>
</dependency>