Quartz集群增強版_00.How to use?(如何使用)
Quartz集群增強版_00.How to use?(如何使用)
開源地址 https://github.com/funnyzpc/quartz
表的基本結構
總的來說任務的配置及開發基本遵從上圖的表的基本關系,除 app 以及 node 之外均需要手動手動配置,app 及 node 在執行端啟動的時候會自動生成對應 app 以及 node 的數據 ~
后管配置
先看一下后管的基本頁面~
因為 app 與 node 是一對多的關系,這里就放到一個page下:
-
![]()
這里需要說明的是
app與node一般無需新增,如果特殊情況下請參照下圖:
app新增
node新增
因為node必須關聯已有的app才可新增,新增入口在app列表中
另外,需要說明的是:
-
如果執行端獲取不到宿
主機IP以及主機名稱會隨機生成一個同名的主機IP以及主機名稱,此時在管理端手動新增就毫無意義了刪除
-
![]()
-
刪除應用必須先刪除應用關聯的節點(
node),節點被刪除則節點對應的執行端無法執行其任務,刪除應用也是 -
刪除應用或節點不會變更任務及執行項的狀態,也不會刪除任務及執行項,沒有節點的執行項不會執行也會定期被清理
啟用/關閉
-
![]()
啟用與關閉只操作節點或應用,關閉節點則節點下的所有任務均不會執行,關閉應用則應用關聯的所有結點都不會執行任務,同時這個操作也不會變更任務或執行項~
再看看節點任務及執行配置:
任務/執行配置是管理端主要任務,執行配置使用關聯任務配置(PID)關聯相應的任務(job),執行項(execute)是不可獨立存在的!
新增任務配置
-
![]()
應用名稱/調度名稱就是自動或手動配置的
應用信息
任務狀態在配置時僅可有 初始化(INIT)/正常執行(EXECUTING) 這兩種狀態,如果只是配置不想立即執行就選 初始化(INIT)新增執行配置-CRON時間任務
-
![]()
任務類型僅可為簡單任務(SIMPLE)或表達式(CRON)的時間項的任務,兩種類型的執行配置(
execute)填寫的字段會有區別
CRON任務的CRON表達式是必填項,時區現階段默認是Asia/Shanghai,后續會改成從系統獲取默認
開始時間一般不填則默認就是-1,新增提交后是按當前時間補充
結束時間也是非必填的,結束時間默認也是-1,結束時間如果是-1則在執行完最后一次任務之后會補充為最后一次執行時間新增執行配置-SIMPLE時間任務
-
![]()
圖中圈出的為必填項,需要說明的是:如果
執行結束時間與執行次數均設置,具體任務執行時會依限制范圍最小的為實際執行,比如設置的結束時間較長但是執行次數只有幾次,那最終大概率只會以執行次數為限制執行另外,對于執行配置,當執行完成后,對應的
執行配置僅可刪除不可 修改或啟停,已經完成的對此類操作是沒有意義的,不如新增一個執行配置
管理端開發配置及集成
這里僅以springboot為例:
- 添加依賴,如果有maven私服建議放到私服
<dependency>
<groupId>org.quartz-scheduler.internal</groupId>
<artifactId>quartz-client</artifactId>
<version>2.3.2</version>
<!-- 這是本地引入,建議放到私服-->
<scope>system</scope>
<systemPath>${pom.basedir}/src/main/resources/lib/quartz-client-2.3.2.jar</systemPath>
</dependency>
- 啟動類需要排除自動裝配
// 這一行是重點!
@SpringBootApplication(exclude = {QuartzAutoConfiguration.class})
public class MeeAdminApplication {
/**
* 日志
*/
private static final Logger LOG= LoggerFactory.getLogger(MeeAdminApplication.class);
public static void main(String[] args)throws Exception {
ConfigurableApplicationContext application = SpringApplication.run(MeeAdminApplication.class, args);
Environment env = application.getEnvironment();
String ip = InetAddress.getLocalHost().getHostAddress();
String port = env.getProperty("server.port");
String path = env.getProperty("server.servlet.context-path");
LOG.info("\n\t----------------------------------------------------------\n\t" +
"Application MeeAdminApplication is running!\n\t" +
"Local: \t\thttp://localhost:" + port + path + "/\n\t" +
"External: \thttp://" + ip + ":" + port + path + "/\n\t" +
"----------------------------------------------------------");
}
}
- 需要配置一個實例以使用
@Service
public final class QrtzJobServiceImpl implements QrtzJobService {
/**
* 日志
*/
private static final Logger LOG = LoggerFactory.getLogger(QrtzJobServiceImpl.class);
/**
* quartz定時任務api
*/
private final Scheduler scheduler;
public QrtzJobServiceImpl(DataSource dataSource) {
this.scheduler = new StdScheduler(dataSource);
}
}
- 調用sdk
@Override
public MeeResult<Integer> updateJobState(String job_id,String state) {
Object[] result = scheduler.updateJobStateInAll(job_id,state);
int updateCount = (int)result[0];
if(updateCount>0){
return ResultBuild.build(updateCount);
}else{
return ResultBuild.fail((String)result[1]);
}
}
Scheduler 提供了多種多樣的api,注意部分接口的區別:

如果管理端與執行端一體 則無需引入client依賴(quartz-client),也無需在啟動類中排除自動裝配(QuartzAutoConfiguration),使用sdk也無需使用構造方式傳入database,僅此即可:
@Autowired
private Scheduler scheduler;
執行端開發配置及集成
- 引入依賴同時排除原生Quartz
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
<version>${spring-boot-current.version}</version>
<exclusions>
<exclusion>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.quartz-scheduler.internal</groupId>
<artifactId>quartz-core</artifactId>
<version>2.3.2</version>
<!-- 這是本地引入,建議放到私服-->
<scope>system</scope>
<systemPath>${pom.basedir}/src/main/resources/lib/quartz-core-2.3.2.jar</systemPath>
</dependency>
- 添加依賴配置項
### ----------- quartz ------------------
spring.quartz.job-store-type=jdbc
spring.quartz.properties.org.quartz.jobStore.class=org.springframework.scheduling.quartz.LocalDataSourceJobStore
spring.quartz.properties.org.quartz.jobStore.clusterCheckinInterval=6000
spring.quartz.properties.org.quartz.jobStore.driverDelegateClass=org.jdbcjobstore.impl.org.quartz.StdJDBCDelegate
spring.quartz.properties.org.quartz.jobStore.isClustered=true
# 表名前綴
spring.quartz.properties.org.quartz.jobStore.tablePrefix=QRTZ_
spring.quartz.properties.org.quartz.scheduler.instanceName=${spring.application.name}
#spring.quartz.properties.org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
spring.quartz.properties.org.quartz.threadPool.class=org.quartz.impl.MeeThreadPool
# 線程數配置
spring.quartz.properties.org.quartz.threadPool.threadCount=10
spring.quartz.properties.org.quartz.threadPool.threadPriority=5
# 綫程繼承初始化線程的上下文類加載器
spring.quartz.properties.org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread=true
#Whether to enable pessimistic lock to control trigger concurrency in the cluster 是否啟用悲觀鎖來控制集群中的觸發并發
spring.quartz.properties.org.quartz.jobStore.acquireTriggersWithinLock=true
配置項里面 要注意線程數的配置,如果使用的 MeeThreadPool 則threadCount為最大線程數,核心線程數 threadCount-2 ,最少為2,具體多少按實際CPU核心個數以及是否是IO密集型還是CPU密集型來配置即可~
其次要注意 tablePrefix 如果表名有變更則按照變更后的表名前綴配置即可
- 定義一個任務
- 如果使用的是
spring提供的QuartzJobBean來開發:
import com.mee.quartz.util.DateUtil; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.quartz.impl.QrtzExecute; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.quartz.QuartzJobBean; import javax.sql.DataSource; public class ATestJob extends QuartzJobBean { private static final Logger log = LoggerFactory.getLogger(ATestJob.class); @Override protected void executeInternal(JobExecutionContext context) throws JobExecutionException { try { log.info("===>ATestJob::executeInternal {}-{} : {}-{}<===" ,context.getJobId(),context.getExecuteId(),context.getJobType(),context.getJobClassName()); } catch (Exception e) { throw new JobExecutionException(e); } } }- 如果使用的是
Quartz提供的Job接口來開發,也可:
import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.quartz.impl.QrtzExecute; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.concurrent.TimeUnit; public class Job01TestService implements Job { private static final Logger LOGGER = LoggerFactory.getLogger(Job01TestService.class); @Override public void execute(JobExecutionContext context) throws JobExecutionException { LOGGER.info("=>>{}-{}.{}-{}",context.getJobId(),context.getExecuteId(),context.getJobType(),context.getJobClassName()); } } - 如果使用的是
以上兩種方式皆可,需要注意的是,不管是繼承 QuartzJobBean 還是實現的 ``Job,均無需將類著名為spring bean類(@Service or @Component),Quartz內部自會創建任務類為spring bean ~
開發注意事項
- 使用
quartz-client添加的任務一般最晚會在5秒之后執行,因為任務輪詢是5秒一輪詢 - 執行端執行異常(
Quartz內的非業務的)的任務最晚在15S之后恢復任務執行,因為集群/缺火處理是15秒一輪詢 - 添加的任務如果不執行首先則要注意
spring.quartz.properties.org.quartz.scheduler.instanceName配置項是否有配置,這個配置項對應app表中的application字段 - 實際任務如有日志出現 任務延遲,建議排查宿
主機資源是否占滿,或者線程數配置是否合理











浙公網安備 33010602011771號