功能特性
本節更詳細地介紹了 Spring Cloud Task,包括如何使用它、如何配置它以及適當的擴充套件點。
Spring Cloud Task 的生命週期
在大多數情況下,現代雲環境圍繞著那些預期不會終止的程序而設計。如果它們確實終止了,通常會重新啟動。雖然大多數平臺都有某種方式執行一個終止時不會被重新啟動的程序,但其執行結果通常無法以可消費的方式維護。Spring Cloud Task 提供了在環境中執行短期程序並記錄結果的能力。這樣做允許圍繞短期程序構建微服務架構,並透過訊息整合任務,實現更長時間執行的服務。
雖然此功能在雲環境中很有用,但在傳統部署模型中也可能出現同樣的問題。當使用 cron 等排程器執行 Spring Boot 應用程式時,能夠在應用程式完成後監控其結果會很有用。
Spring Cloud Task 採用這樣一種方法:Spring Boot 應用程式可以有開始和結束,並且仍然是成功的。批處理應用程式就是一種如何實現預期會終止(且通常是短期)的程序並使其發揮作用的示例。
Spring Cloud Task 會記錄給定任務的生命週期事件。大多數長時間執行的程序(以大多數 Web 應用程式為代表)不儲存它們的生命週期事件。而 Spring Cloud Task 的核心任務則會儲存。
生命週期由一次任務執行組成。這是一次 Spring Boot 應用程式的物理執行,該應用程式被配置為一個任務(即,它具有 Spring Cloud Task 依賴項)。
在任務開始時,在任何 CommandLineRunner
或 ApplicationRunner
實現執行之前,會在 TaskRepository
中建立一個記錄開始事件的條目。此事件透過 Spring Framework 觸發 SmartLifecycle#start
來觸發。這向系統表明所有 bean 都已準備就緒,並且在此之前會執行 Spring Boot 提供的任何 CommandLineRunner
或 ApplicationRunner
實現。
任務的記錄僅在 ApplicationContext 成功引導時發生。如果上下文完全無法引導,則不記錄該任務的執行。 |
在 Spring Boot 的所有 *Runner#run
呼叫完成後,或者 ApplicationContext
失敗(由 ApplicationFailedEvent
指示)時,任務執行的結果會在倉庫中更新。
如果應用程式要求在任務完成時關閉 ApplicationContext (所有 *Runner#run 方法都已呼叫且任務倉庫已更新),則將屬性 spring.cloud.task.closecontextEnabled 設定為 true。 |
TaskExecution
儲存在 TaskRepository
中的資訊在 TaskExecution
類中建模,包含以下資訊
欄位 | 描述 |
---|---|
|
任務執行的唯一 ID。 |
|
由 |
|
任務的名稱,由配置的 |
|
任務啟動的時間,由 |
|
任務完成的時間,由 |
|
退出時可用的任何資訊。這可以透過 |
|
如果異常是任務結束的原因(由 |
|
傳遞給可執行 boot 應用程式的字串命令列引數的 |
對映退出碼
當任務完成時,它會嘗試向作業系統返回一個退出碼。如果我們看看我們的原始示例,可以看到我們沒有控制應用程式的這一方面。因此,如果丟擲異常,JVM 返回的程式碼可能對你的除錯有用,也可能沒有用。
因此,Spring Boot 提供了一個介面 ExitCodeExceptionMapper
,允許你將未捕獲的異常對映到退出碼。這樣做可以讓你在退出碼級別指示出了什麼問題。此外,透過以這種方式對映退出碼,Spring Cloud Task 會記錄返回的退出碼。
如果任務因 SIG-INT 或 SIG-TERM 而終止,退出碼為零,除非程式碼中另有指定。
任務執行時,退出碼在倉庫中儲存為 null。任務完成後,根據本節前面描述的指南儲存相應的退出碼。 |
配置
Spring Cloud Task 提供了開箱即用的配置,如 DefaultTaskConfigurer
和 SimpleTaskConfiguration
類中定義的那樣。本節將介紹預設配置以及如何根據需要自定義 Spring Cloud Task。
DataSource
Spring Cloud Task 使用資料來源來儲存任務執行結果。預設情況下,我們提供了一個記憶體中的 H2 例項,以提供簡單的開發引導方法。然而,在生產環境中,你可能希望配置自己的 DataSource
。
如果你的應用程式只使用一個 DataSource
,並且它既作為你的業務 schema 又作為任務倉庫,你只需提供任何 DataSource
(最簡單的方法是透過 Spring Boot 的配置約定)。Spring Cloud Task 會自動將此 DataSource
用於倉庫。
如果你的應用程式使用多個 DataSource
,你需要使用適當的 DataSource
配置任務倉庫。此自定義可以透過 TaskConfigurer
的實現來完成。
表字首
TaskRepository
的一個可修改屬性是任務表的表字首。預設情況下,它們都以 TASK_
開頭。TASK_EXECUTION
和 TASK_EXECUTION_PARAMS
是兩個示例。然而,修改此字首可能有潛在的原因。如果 schema 名稱需要新增到表名稱前面,或者在同一個 schema 中需要多組任務表,則必須更改表字首。你可以透過將 spring.cloud.task.tablePrefix
設定為你需要的字首來完成此操作,如下所示
spring.cloud.task.tablePrefix=yourPrefix
透過使用 spring.cloud.task.tablePrefix
,使用者承擔建立任務表的責任,這些任務表需要滿足任務表 schema 的標準,但要進行使用者業務所需的修改。在建立自己的任務 DDL 時,你可以利用 Spring Cloud Task Schema 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 方法就足夠了。然而,可能需要從頭開始實現自己的元件。
使用者不應直接使用 TaskConfigurer 的 getter 方法,除非他們使用它來提供實現以暴露為 Spring Bean。 |
任務執行監聽器
TaskExecutionListener
允許你註冊任務生命週期中發生的特定事件的監聽器。為此,建立一個實現 TaskExecutionListener
介面的類。實現 TaskExecutionListener
介面的類會收到以下事件通知
-
onTaskStartup
:在將TaskExecution
儲存到TaskRepository
之前。 -
onTaskEnd
:在更新TaskRepository
中的TaskExecution
條目並標記任務的最終狀態之前。 -
onTaskFailed
:在任務丟擲未處理異常時呼叫onTaskEnd
方法之前。
Spring Cloud Task 還允許你使用以下方法註解將 TaskExecution
監聽器新增到 bean 中的方法
-
@BeforeTask
:在將TaskExecution
儲存到TaskRepository
之前 -
@AfterTask
:在更新TaskExecution
中的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
方法。然而,TaskExecutionListener
的其他事件處理程式(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 和 Native Compilation 的單例項用法
在使用 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 的自動配置。這可以透過向你的 Task 應用程式新增以下註解來完成
@EnableAutoConfiguration(exclude={SimpleTaskAutoConfiguration.class})
你也可以透過將 spring.cloud.task.autoconfiguration.enabled
屬性設定為 false
來停用 Task 自動配置。
關閉上下文
如果應用程式要求在任務完成時關閉 ApplicationContext
(所有 *Runner#run
方法都已呼叫且任務倉庫已更新),則將屬性 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>