Quartz叢集增強版_00.How to use?(如何使用)
轉載請著名出處 https://www.cnblogs.com/funnyzpc/p/18540378
開源地址 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
欄位 - 實際任務如有日誌出現 任務延遲,建議排查宿
主機資源
是否佔滿,或者執行緒數
配置是否合理