跳至主要内容

排程與叢集鎖

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-autoshedlock 表行為
createcreate-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 與大量 jobQuartz 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。filenotification 會透過 requires 自動帶入它;沒有 排程需求的應用不必安裝。SchedulingConfig 是應用擁有的組態 seam,而 ShedLockEntry 是 可同步的 canonical schema mapping。

API 參考