對xxl-job進行simpleTrigger並動態創建任務擴展


業務場景

需求上要求能實現quartz的simpleTrigger任務,同時還需要動態的創建任務而非在控制面板上創建,查閱xxl-job官方文檔發現simpelTrigger其暫時還躺在to do list,而動態創建可以調用JobInfoController其add和start接口(但是有個弊端,start/stop/remove等方法都只要求傳送id,這點上可以自己擴展接口實現),還需要放開登錄權限,接下來就老夫上去就上一梭子,開干。

job_info字段調整說明

CREATE TABLE `XXL_JOB_QRTZ_TRIGGER_INFO` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `job_group` int(11) NOT NULL COMMENT '執行器主鍵ID',
  `job_cron` varchar(128) DEFAULT NULL COMMENT '任務執行CRON',
  `job_desc` varchar(255) NOT NULL,
  `add_time` datetime DEFAULT NULL,
  `update_time` datetime DEFAULT NULL,
  `author` varchar(64) DEFAULT NULL COMMENT '作者',
  `alarm_email` varchar(255) DEFAULT NULL COMMENT '報警郵件',
  `executor_route_strategy` varchar(50) DEFAULT NULL COMMENT '執行器路由策略',
  `executor_handler` varchar(255) DEFAULT NULL COMMENT '執行器任務handler',
  `executor_param` varchar(512) DEFAULT NULL COMMENT '執行器任務參數',
  `executor_block_strategy` varchar(50) DEFAULT NULL COMMENT '阻塞處理策略',
  `executor_timeout` int(11) NOT NULL DEFAULT '0' COMMENT '任務執行超時時間,單位秒',
  `executor_fail_retry_count` int(11) NOT NULL DEFAULT '0' COMMENT '失敗重試次數',
  `glue_type` varchar(50) NOT NULL COMMENT 'GLUE類型',
  `glue_source` mediumtext COMMENT 'GLUE源代碼',
  `glue_remark` varchar(128) DEFAULT NULL COMMENT 'GLUE備注',
  `glue_updatetime` datetime DEFAULT NULL COMMENT 'GLUE更新時間',
  `child_jobid` varchar(255) DEFAULT NULL COMMENT '子任務ID,多個逗號分隔',
  `ext_reamrk` varchar(255) DEFAULT NULL,
  `job_start_time` bigint(20) DEFAULT NULL COMMENT 'trigger開始時間於當前時間的時間間隔 單位毫秒\n',
  `job_end_time` datetime DEFAULT NULL COMMENT 'trigger結束時間',
  `job_repeat_count` bigint(7) DEFAULT '-1' COMMENT 'simple_trigger 執行次數 ',
  `job_repeat_interval` bigint(12) DEFAULT NULL COMMENT 'simple_trigger 時間間隔 單位毫秒',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
  • job_cron設為空,支持simpleTrigger;
  • ext_reamrk自定義擴展字段,可以根據它來刷選job從而避免start/stop/remove接口只有id作為參數;
  • job_repeat_count,simplerTrigger的執行次數,默認-1即為無限次,0的話是執行1次;
  • job_repeat_interval,simplerTrigger每次執行的時間間隔,單位毫秒;
  • job_start_time,trigger開始時間和當前時間的時間間隔,單位毫秒;
  • job_end_time,trigger結束時間

重寫啟動任務

xxl-job在新建任務的時候只是把job數據保存到數據庫里,只有啟動的時候才會創建jobDetailtrigger並由scheduler來啟動job。

重寫XxlJobDynamicScheduleraddJob方法:根據jobInfo中的值構建cron的trigger還是simple的trigger。

public static boolean addJob(XxlJobInfo xxlJobInfo) throws SchedulerException {
        String jobName = String.valueOf(xxlJobInfo.getId());
        String cronExpression = xxlJobInfo.getJobCron();
        Integer jobRepeatCount = xxlJobInfo.getJobRepeatCount();
        Long jobRepeatInterval = xxlJobInfo.getJobRepeatInterval();

    	// 1、job key
        TriggerKey triggerKey = TriggerKey.triggerKey(jobName);
        JobKey jobKey = new JobKey(jobName);

        // 2、valid trigger
        if(scheduler.checkExists(triggerKey)) {
            return true;
        }

        // 3.1、corn trigger
        Trigger trigger = null;
        if (!StringUtils.isEmpty(cronExpression)) {
            CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing();   // withMisfireHandlingInstructionDoNothing 忽略掉調度終止過程中忽略的調度
            TriggerBuilder<CronTrigger> builder = TriggerBuilder.newTrigger().withIdentity(triggerKey)
                    .withSchedule(cronScheduleBuilder)
                    .endAt(xxlJobInfo.getJobEndTime());
            Optional.ofNullable(xxlJobInfo.getJobStartTime())
                    .ifPresent(start -> builder.startAt(new Date(System.currentTimeMillis() + start)));
            trigger = builder.build();
        } else
        // 3.2、simple trigger
        if (Objects.nonNull(jobRepeatInterval) && Objects.nonNull(jobRepeatCount)) {
            SimpleScheduleBuilder simpleScheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
                    .withIntervalInMilliseconds(jobRepeatInterval)
                    .withRepeatCount(jobRepeatCount);
            TriggerBuilder<SimpleTrigger> builder = TriggerBuilder.newTrigger().withIdentity(triggerKey)
                    .withSchedule(simpleScheduleBuilder)
                    .endAt(xxlJobInfo.getJobEndTime());
            Optional.ofNullable(xxlJobInfo.getJobStartTime())
                    .ifPresent(start -> builder.startAt(new Date(System.currentTimeMillis() + start)));
            trigger = builder.build();
        }
        // 3.3、valid trigger
        if(Objects.isNull(trigger)) {
            return true;
        }

        // 4、job detail
		Class<? extends Job> jobClass_ = RemoteHttpJobBean.class;   // Class.forName(jobInfo.getJobClass());
		JobDetail jobDetail = JobBuilder.newJob(jobClass_).withIdentity(jobKey).build();

        /*if (jobInfo.getJobData()!=null) {
        	JobDataMap jobDataMap = jobDetail.getJobDataMap();
        	jobDataMap.putAll(JacksonUtil.readValue(jobInfo.getJobData(), Map.class));	
        	// JobExecutionContext context.getMergedJobDataMap().get("mailGuid");
		}*/
        
        // 5、schedule job
        Date date = scheduler.scheduleJob(jobDetail, trigger);

        logger.info(">>>>>>>>>>> addJob success(quartz), jobDetail:{}, trigger:{}, date:{}", jobDetail, trigger, date);
        return true;
    }

效果圖

img

image-20190508165249933

image-20190508165315058

可以看到將數據庫里3任務改為間隔3秒,job_repeat_count為1,任務實際會執行2次。

額外的工作

  1. 雖然支持cron或simple,但是在控制台節目只能維護cron的trigger,並且優先cron,同時cron設為可以為空,但是管理平台上沒有simple的相關數據,如果需要的話要重新修改對應的頁面和add和update的邏輯;
  2. job狀態取的是trigger的狀態,所以可能看到的是simpleTrigger的狀態。
  3. 目前job的trigger是在cron和simple中二者取一,但是也可以擴展啟動任務的方法,使其支持擴展多trigger,但是triggerKey需要重新定義而非取jobName(因為trigger的hash是triggerKey的hash),本身xxl-job的jobKey取的是job的id,triggerKey取的也是job的id,沒有使用到groupName。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM