1. 概述
在本教程中,我們將探討使用 JobRunr 在 Java 中進行分佈式後台任務調度和處理,並將其與 Spring 集成。
2. 關於 JobRunr
JobRunr 是一個我們可以嵌入到我們應用程序中的庫,它允許我們使用 Java 8 lambda 安排後台任務。我們可以使用我們現有的 Spring 服務中的任何方法來創建任務,而無需實現接口。一個任務可以是短的也可以是長時間運行的,並且它會被自動卸載到後台線程中,以避免當前 Web 請求被阻塞。
為了完成任務,JobRunr 會分析 Java 8 lambda,將其序列化為 JSON,並將其存儲到關係型數據庫或 NoSQL 數據存儲中。
3. JobRunr 的特性
如果我們的系統產生過多的後台任務,並且服務器負載過高,我們可以輕鬆地通過添加更多應用程序實例來進行水平擴展。JobRunr 將自動分擔負載,並將所有任務分發到我們應用程序的不同實例上。
它還包含一個帶有指數退避策略的自動重試功能,用於處理失敗的任務。此外,JobRunr 還內置了一個儀表盤,允許我們監控所有任務。JobRunr 具有自我維護功能——成功完成的任務將在可配置的時間後自動刪除,因此無需手動執行存儲清理。
4. 安裝配置
為了簡化操作,我們將使用內存數據存儲來存儲所有與工作相關的資料。
4.1. Maven 配置
讓我們直接進入 Java 代碼。但在進行之前,我們需要在我們的 <em >pom.xml</em> 文件中聲明以下 Maven 依賴:
<dependency>
<groupId>org.jobrunr</groupId>
<artifactId>jobrunr-spring-boot-starter</artifactId>
<version>5.1.7</version>
</dependency>4.2. Spring Integration
在直接開始創建後台任務之前,我們需要初始化 JobRunr。由於我們使用了 jobrunr-spring-boot-starter 依賴項,這非常簡單。我們只需要在 application.properties 中添加一些屬性即可:
org.jobrunr.background-job-server.enabled=true
org.jobrunr.dashboard.enabled=true第一個屬性告訴 JobRunr 我們想要啓動一個 BackgroundJobServer 實例,該實例負責處理作業。第二個屬性告訴 JobRunr 啓動嵌入式儀表盤。
默認情況下,jobrunr-spring-boot-starter 將嘗試使用您現有的 DataSource 以便在關係數據庫中存儲所有作業相關的信息。
但是,由於我們將會使用內存數據存儲,因此我們需要提供一個 StorageProvider Bean:
@Bean
public StorageProvider storageProvider(JobMapper jobMapper) {
InMemoryStorageProvider storageProvider = new InMemoryStorageProvider();
storageProvider.setJobMapper(new JobMapper(new JacksonJsonMapper()));
return storageProvider;
}5. 使用方法
現在,讓我們瞭解如何使用 JobRunr 在 Spring 中創建和安排後台任務。
5.1. 注入依賴
當我們需要創建任務時,我們需要注入 <a href="https://www.javadoc.io/doc/org.jobrunr/jobrunr/latest/org/jobrunr/scheduling/JobScheduler.html">JobScheduler</a> 以及我們現有的 Spring 服務,其中包含我們想要創建任務的方法,在本例中是 <em>SampleJobService</em>:
@Inject
private JobScheduler jobScheduler;
@Inject
private SampleJobService sampleJobService;JobScheduler 類來自 JobRunr,允許我們排隊或安排新的後台任務。
SampleJobService 可以是我們在 Spring 中現有的任何服務,該服務包含一個可能在 Web 請求中耗費過多的方法。 還可以是調用其他外部服務的任何方法,以便我們可以在 JobRunr 遇到異常時重試該方法,從而增加彈性。
5.2. 創建後台運行任務
現在我們已經定義了依賴項,可以使用 enqueue 方法創建後台運行任務:
jobScheduler.enqueue(() -> sampleJobService.executeSampleJob());函數可以有參數,就像任何其他 lambda 函數一樣:
jobScheduler.enqueue(() -> sampleJobService.executeSampleJob("some string"));此行確保 lambda –包括類型、方法和參數– 被序列化為 JSON 並持久化到存儲(例如,RDBMS,如 Oracle、Postgres、MySQL 或 MariaDB,或 NoSQL 數據庫)。
多個 BackgroundJobServer 中的線程池將立即以先進先出(FIFO)的方式執行這些排隊的後台任務。 JobRunr 通過樂觀鎖機制保證你的任務由單個工作進程執行。
5.3. 將作業安排為未來
我們可以使用 schedule 方法將作業安排為未來:
jobScheduler.schedule(LocalDateTime.now().plusHours(5), () -> sampleJobService.executeSampleJob());5.4. 週期性調度任務
如果需要週期性執行任務,則需要使用 scheduleRecurrently 方法:
jobScheduler.scheduleRecurrently(Cron.hourly(), () -> sampleJobService.executeSampleJob());5.5. 使用 <em @Job 註解進行標註
為了控制所有作業方面,我們可以使用 <em @Job 註解標註我們的服務方法。這允許我們在儀表板中設置顯示名稱,並在作業失敗時配置重試次數。
@Job(name = "The sample job with variable %0", retries = 2)
public void executeSampleJob(String variable) {
...
}我們甚至可以使用通過 String.format() 語法傳遞給我們的任務的變量,顯示名稱中。
如果我們在特定用例中想要僅在特定異常情況下重試某個任務,我們可以編寫自定義的 ElectStateFilter,其中我們能夠訪問 Job 並且完全控制如何繼續執行。
6. 儀表盤
JobRunr 內置了一個儀表盤,允許我們監控所有任務。 您可以在 http://localhost:8000 找到它,並檢查所有任務,包括所有重複任務以及處理所有排隊的任務所需的時間的估算。
事情可能會出錯,例如,SSL 證書過期或磁盤已滿。 JobRunr 默認情況下將使用指數退避策略重新安排後台任務。 如果後台任務失敗 10 次,才會進入 失敗 狀態。 然後您可以決定在根原因解決後重新排隊失敗的任務。
所有這些都可以在儀表盤中查看,包括每個重試的精確錯誤消息以及任務失敗的原因的完整堆棧跟蹤。
7. 結論
在本文中,我們使用 JobRunr 和 jobrunr-spring-boot-starter 構建了我們的第一個基本調度器。 本教程的關鍵要點是,我們只需一行代碼就能創建任務,並且無需基於 XML 的配置或實現接口。