排程與叢集鎖
AppFuse Server 傳遞 Spring Scheduling、Quartz 與 ShedLock 所需依賴;應用程式決定要啟用哪些
排程、如何設定觸發週期,以及哪些任務需要跨節點互斥。參考應用的 scheduling Feature 使用
Spring @Scheduled 搭配 ShedLock JDBC provider。
快速開始
在應用層配置排程與 ShedLock:
@Configuration
@EnableScheduling
@EnableSchedulerLock(
defaultLockAtMostFor = "PT10M",
order = Ordered.HIGHEST_PRECEDENCE)
public class SchedulingConfig {
@Bean
LockProvider lockProvider(DataSource dataSource) {
return new JdbcTemplateLockProvider(
JdbcTemplateLockProvider.Configuration.builder()
.withJdbcTemplate(new JdbcTemplate(dataSource))
.usingDbTime()
.build());
}
}
需要每個 tick 只執行一次的任務加上鎖:
@Scheduled(cron = "${app.file.cleanup-cron}")
@SchedulerLock(name = "file-staging-cleanup", lockAtMostFor = "PT30M")
public void cleanup() {
cleanupTask.run();
}
usingDbTime() 讓所有節點以資料庫時間判定鎖的有效期,避免應用節點時鐘偏移造成提早或延後
釋放。
order = Ordered.HIGHEST_PRECEDENCE 讓 locking advisor 在同一排程方法的 transaction advisor
外層執行:先取得鎖,再開始業務交易;交易 commit/rollback 完成後才釋放鎖。這避免業務交易
尚未完成時鎖就先被其他節點取得,也消除多個 advisor 使用預設最低優先序時的順序不確定性。
ShedLock JDBC provider 自己的鎖 SQL 另以 REQUIRES_NEW 交易執行,因此此設定是在固定業務方法
的 advisor 邊界,不是用來修復取鎖 SQL 的交易提交。
shedlock Schema
ShedLock JDBC provider 直接操作下列四個欄位:
| 欄位 | 用途 |
|---|---|
name | 鎖名稱與主鍵 |
lock_until | 鎖的到期時間 |
locked_at | 取得鎖的時間 |
locked_by | 持鎖節點識別 |
AppFuse 參考應用提供不含 repository 或業務操作的 ShedLockEntry JPA entity,目的只在於把
這張基礎設施表納入 Hibernate schema management。行為因此與其他 Entity 完全一致:
spring.jpa.hibernate.ddl-auto | shedlock 表行為 |
|---|---|
create/create-drop | 建立表 |
update | 缺表時建立,既有表依 Hibernate 規則更新 |
validate | 驗證表與欄位,缺少或不相容時停止啟動 |
none | 不建立也不驗證;部署流程須自行提供正確 schema |
欄位型別由 Hibernate dialect 產生,不使用跨資料庫的手寫 DDL。例如 SQL Server 的日期時間
欄位會使用 dialect 對應型別,不會誤把 TIMESTAMP 當成 rowversion。
若應用不使用參考 Feature,仍可自行宣告等價的 JPA mapping,或由 Flyway/Liquibase/DBA 建立官方 ShedLock schema。
選擇正確的叢集協調方式
| 任務 | 建議方式 |
|---|---|
| 清理、對帳、單次掃描 | ShedLock 或可證明的冪等 |
| 可水平擴展的 Queue/Outbox | 資料列原子認領,讓多節點共同 drain |
| 需要持久 trigger、misfire 與大量 job | Quartz JDBC cluster |
通知 Outbox 不應套全域 @SchedulerLock:它已透過資料列認領避免重複遞送,同時保留多節點
並行吞吐。檔案 orphan sweep、staging cleanup 這類 run-once 任務則適合 ShedLock。
配置原則
- cron、fixed delay 與 batch size 等可變值放在
app.<feature>.*。 lockAtMostFor應略長於任務合理的最長執行時間,作為節點崩潰後的安全上限。- 鎖名稱必須在整個應用中唯一,且部署後保持穩定。
- 多租戶應用的背景執行緒沒有 HTTP tenant context;寫入租戶資料前須明確切入對應租戶。
- Tenantless 應用也不能把「沒有 principal」當成自動取得所有資源權限。
Feature 生命週期
scheduling 是 optional Feature。file 與 notification 會透過 requires 自動帶入它;沒有
排程需求的應用不必安裝。SchedulingConfig 是應用擁有的組態 seam,而 ShedLockEntry 是
可同步的 canonical schema mapping。