XXL-job源码公司版本个阅读心得


从别人那边拷贝的原理图
在这里插入图片描述
公司版本的xxl-job,东拼西凑的版本
与V2.0.0 这个版本相似
https://www.xuxueli.com/xxl-job/#7.11%20版本%20V1.5.2%20特性[2017-02-28]
代码地址
https://gitee.com/xuxueli0323/xxl-job.git

调度中心

@Bean(initMethod = "start", destroyMethod = "destroy")
public JobDynamicScheduler getXxlJobDynamicScheduler(SchedulerFactoryBean schedulerFactory){

    Scheduler scheduler = schedulerFactory.getScheduler();

    JobDynamicScheduler xxlJobDynamicScheduler = new JobDynamicScheduler();
    xxlJobDynamicScheduler.setScheduler(scheduler);

    return xxlJobDynamicScheduler;
}

启动

public void start() throws Exception {
    // valid
    Assert.notNull(scheduler, "quartz scheduler is null");

    // init i18n
    initI18n();

    //job注册线程
    JobRegistryMonitorHelper.getInstance().start();

    //job失败线程
    JobFailMonitorHelper.getInstance().start();

    //调度中心rpc客户端
    initRpcProvider();

    logger.info(">>>>>>>>> init dbaas-job admin success.");
}

运行中

JobRegistryMonitorHelper

一直保持执行器信息的更新,只更新自动注册的执行器,把表h_qrtz_trigger_registry的数据更新到h_qrtz_trigger_group,默认90秒更新一次

public void start(){
    registryThread = new Thread(new Runnable() {
        @Override
        public void run() {
            while (!toStop) {
                try {
                    // auto registry group
                    List<JobGroup> groupList = JobAdminConfig.getAdminConfig().getXxlJobGroupDao().findByAddressType(0);
                    if (CollectionUtils.isNotEmpty(groupList)) {

                        // remove dead address (admin/executor)
                        JobAdminConfig.getAdminConfig().getXxlJobRegistryDao().removeDead(RegistryConfig.DEAD_TIMEOUT);

                        // fresh online address (admin/executor)
                        HashMap<String, List<String>> appAddressMap = new HashMap<String, List<String>>();
                        List<JobRegistry> list = JobAdminConfig.getAdminConfig().getXxlJobRegistryDao().findAll(RegistryConfig.DEAD_TIMEOUT);
                        if (list != null) {
                            for (JobRegistry item: list) {
                                if (RegistryConfig.RegistType.EXECUTOR.name().equals(item.getRegistryGroup())) {
                                    String appName = item.getRegistryKey();
                                    List<String> registryList = appAddressMap.get(appName);
                                    if (registryList == null) {
                                        registryList = new ArrayList<String>();
                                    }

                                    if (!registryList.contains(item.getRegistryValue())) {
                                        registryList.add(item.getRegistryValue());
                                    }
                                    appAddressMap.put(appName, registryList);
                                }
                            }
                        }

                        // fresh group address
                        for (JobGroup group: groupList) {
                            List<String> registryList = appAddressMap.get(group.getAppName());
                            String addressListStr = null;
                            if (CollectionUtils.isNotEmpty(registryList)) {
                                Collections.sort(registryList);
                                addressListStr = StringUtils.join(registryList, ",");
                            }
                            group.setAddressList(addressListStr);
                            JobAdminConfig.getAdminConfig().getXxlJobGroupDao().updateJobGroup(group);
                        }
                    }
                } catch (Exception e) {
                    logger.error("job registry instance error:{}", e);
                }
                try {
                    TimeUnit.SECONDS.sleep(RegistryConfig.BEAT_TIMEOUT);
                } catch (InterruptedException e) {
                    logger.error("job registry instance error:{}", e);
                }
            }
        }
    });
    registryThread.setDaemon(true);
    registryThread.start();
}

JobTriggerPoolHelper

任务触发线程池

private ThreadPoolExecutor triggerPool = new ThreadPoolExecutor(
    32,
    256,
    60L,
    TimeUnit.SECONDS,
    new LinkedBlockingQueue<Runnable>(1000));


public void addTrigger(final int jobId, final TriggerTypeEnum triggerType, final int failRetryCount, final String executorShardingParam, final String executorParam) {
    triggerPool.execute(new Runnable() {
        @Override
        public void run() {
            JobTrigger.trigger(jobId, triggerType, failRetryCount, executorShardingParam, executorParam);
        }
    });
}

定时任务触发

从启动接口开始
JobServiceImplJobServiceImpl

@Override
public JobWrapper<String> start(int id) {
    JobInfo xxlJobInfo = xxlJobInfoDao.loadById(id);
    String group = String.valueOf(xxlJobInfo.getJobGroup());
    String name = String.valueOf(xxlJobInfo.getId());
    String cronExpression = xxlJobInfo.getJobCron();

    try {
        boolean ret = JobDynamicScheduler.addJob(name, group, cronExpression);
        return ret ? JobWrapper.SUCCESS : JobWrapper.FAIL;
    } catch (SchedulerException e) {
        logger.error(e.getMessage(), e);
        return JobWrapper.FAIL;
    }
}

JobDynamicScheduler
把定时任务注册到quartz中

public static boolean addJob(String jobName, String jobGroup, String cronExpression) throws SchedulerException {
    // 1、job key
    TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
    JobKey jobKey = new JobKey(jobName, jobGroup);

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

    // 3、corn trigger
    CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing();   // withMisfireHandlingInstructionDoNothing 忽略掉调度终止过程中忽略的调度
    CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build();

    // 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, cronTrigger);

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

RemoteHttpJobBean

quartz 定时任务和手动任务触发的调用方法一致

@Override
protected void executeInternal(JobExecutionContext context)
    throws JobExecutionException {

    // load jobId
    JobKey jobKey = context.getTrigger().getJobKey();
    Integer jobId = Integer.valueOf(jobKey.getName());

    // trigger
    JobTriggerPoolHelper.trigger(jobId, TriggerTypeEnum.CRON, -1, null, null);
}

手动触发任务

从触发接口开始
JobServiceImpl

@Override
public JobWrapper<String> triggerJob(int id, Map<String, String> params) {
    String executorParam = "";
    if (params != null) {
        executorParam = params.get("executorParam");
        // force cover job param
        if (executorParam == null) {
            executorParam = "";
        }
    } else {
        executorParam = "";
    }

    JobTriggerPoolHelper.trigger(id, TriggerTypeEnum.MANUAL, -1, null, executorParam);
    return JobWrapper.SUCCESS;
}

JobTrigger

public static void trigger(int jobId, TriggerTypeEnum triggerType, int failRetryCount, String executorShardingParam, String executorParam) {
    // load data
    JobInfo jobInfo = JobAdminConfig.getAdminConfig().getXxlJobInfoDao().loadById(jobId);
    if (jobInfo == null) {
        logger.warn(">>>>>>>>>>>> trigger fail, jobId invalid,jobId={}", jobId);
        return;
    }

    Date curTime = new Date();
	//必须时间相同才能触发
    if(jobInfo.getBeginTime() != null && curTime.getTime() < jobInfo.getBeginTime().getTime()) {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm");
        logger.warn(">>>>>>>>>>>> trigger fail, trigger time invalid,jobId={},curTime={},beginTime={}", jobId,df.format(curTime),df.format(jobInfo.getBeginTime()));
        return;
    }

    if(jobInfo.getEndTime() != null && curTime.getTime() > jobInfo.getEndTime().getTime()) {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm");
        logger.warn(">>>>>>>>>>>> trigger fail, trigger time invalid,jobId={},curTime={},endTime={}", jobId,df.
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值