阅读XXL-Job源码-服务端

从XxlJobAdminConfig开始

XxlJobScheduler的init()方法:

1、JobTriggerPoolHelper: 进入start()方法: 会创建两个线程池

java 复制代码
    // fast/slow thread pool
    private ThreadPoolExecutor fastTriggerPool = null;
    private ThreadPoolExecutor slowTriggerPool = null;

2、JobRegistryHelper: 进入start()方法: 会创建一个线程池、创建一个线程 registryMonitorThread 主要是用于实时更新XxlJobGroup注册信息

ini 复制代码
	private ThreadPoolExecutor registryOrRemoveThreadPool = null;
	private Thread registryMonitorThread;

        ...
        registryMonitorThread.setDaemon(true);
        registryMonitorThread.setName("xxl-job, admin JobRegistryMonitorHelper-registryMonitorThread");
        registryMonitorThread.start();

3、JobFailMonitorHelper: 进入start()方法: 主要逻辑是:查询xxl_job_log中的失败状态的日志; 如果有重试,则重试; 去告警处理(比如发邮件);

??疑问:为啥会有triggerCode和handleCode,xxlJob的TriggerInfo和HandleInfo他们的区别是什么?

scss 复制代码
        List<Long> failLogIds = XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().findFailJobLogIds(1000);

        ...
        XxlJobLog log = XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().load(failLogId);
        XxlJobInfo info = XxlJobAdminConfig.getAdminConfig().getXxlJobInfoDao().loadById(log.getJobId());


        // 1、配置重试次数后,会重试
        if (log.getExecutorFailRetryCount() > 0) {
            JobTriggerPoolHelper.trigger(log.getJobId(), TriggerTypeEnum.RETRY, (log.getExecutorFailRetryCount() - 1), log.getExecutorShardingParam(), log.getExecutorParam(), null);
            String retryMsg = "<br><br><span style=\"color:#F39C12;\" > >>>>>>>>>>>" + I18nUtil.getString("jobconf_trigger_type_retry") + "<<<<<<<<<<< </span><br>";
            log.setTriggerMsg(log.getTriggerMsg() + retryMsg);
            XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().updateTriggerInfo(log);
        }
        
        
        // 2、去告警,并返回告警是否成功
            int newAlarmStatus = 0;        // 告警状态:0-默认、-1=锁定状态、1-无需告警、2-告警成功、3-告警失败
            if (info != null) {
                boolean alarmResult = XxlJobAdminConfig.getAdminConfig().getJobAlarmer().alarm(info, log);
                newAlarmStatus = alarmResult ? 2 : 3;
            } else {
                newAlarmStatus = 1;
            }
     //更新 xxl_job_log的 alarmStatus字段
     XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().updateAlarmStatus(failLogId, -1, newAlarmStatus);

4、JobCompleteHelper: 进入start()方法: 会创建一个线程池、一个线程 callbackThreadPool 主要是用来接收处理客户端的回调,并将log更新到db中。 monitorThread 主要是 任务结果丢失处理 的。

ini 复制代码
    private ThreadPoolExecutor callbackThreadPool = null;
    private Thread monitorThread;

5、JobLogReportHelper: 进入start()方法: 会创建一个线程 logrThread 主要是 用于生成XxlJobLogReport,并保存到db中。

arduino 复制代码
    private Thread logrThread;

6、JobScheduleHelper: 进入start()方法: 会创建两个线程

arduino 复制代码
    private Thread scheduleThread;
    private Thread ringThread;

阅读scheduleThread内部的代码: 使用数据库锁先上锁; 再查询 运行中的job任务 List<XxlJobInfo> scheduleList; 再去执行job; 再更新scheduleList;

java 复制代码
// tx start

// 1、pre read 查询 status=运行中,执行时刻为5s以内的 
long nowTime = System.currentTimeMillis();
List<XxlJobInfo> scheduleList = XxlJobAdminConfig.getAdminConfig().getXxlJobInfoDao().scheduleJobQuery(nowTime + PRE_READ_MS, preReadCount);

继续看scheduleThread内部做了什么

上述这段代码表达了:

  • 如果超过了触发时刻5s以上:IF 立刻触发:去触发job ELSE:更新下次有效时间。
  • 如果触发时刻过了不超过5s:去触发job,更新下次有效时间。如果下次触发在5s以内,则pushTimeRing(ringSecond, jobInfo.getId()),并更新下次有效时间。
  • ELSE:pushTimeRing(ringSecond, jobInfo.getId()),并更新下次有效时间。

补充:refreshNextValidTime(jobInfo, new Date()) 内部会计算出下次触发时刻。

最后再更新scheduleList

scss 复制代码
// 3、update trigger info
    for (XxlJobInfo jobInfo: scheduleList) {
        XxlJobAdminConfig.getAdminConfig().getXxlJobInfoDao().scheduleUpdate(jobInfo);
    }

在看ringThread内部:他去处理pushTimeRing()的数据。

每秒从pushTimeRing()中的map中去获取要执行的job list,并执行jobInfo。

因为scheduleThread是取5s内的存入map,ringThread再从map中一秒一秒的取jobInfo list。

再取循环执行此秒要执行的jobInfo list,去触发执行。

一秒一秒的取jobInfo。

触发执行的方法JobTriggerPoolHelper.trigger():就是将触发任务放入触发线程中异步消费(最终是http请求调用客户端去执行)

总结:上述大致描述了一下整体流程,具体的内部细节有需要需可以直接看源码,这里就不详细解读了(其实是本人没有细读代码,只粗读了一遍🥱)。

相关推荐
好好研究2 小时前
Spring Boot - Thymeleaf模板引擎
java·spring boot·后端·thymeleaf
爬山算法2 小时前
Hibernate(76)如何在混合持久化环境中使用Hibernate?
java·后端·hibernate
她说..2 小时前
策略模式+工厂模式实现单接口适配多审核节点
java·spring boot·后端·spring·简单工厂模式·策略模式
csdn_aspnet2 小时前
ASP.NET 8 - Cookie 身份验证
后端·asp.net·cookie·.net8
笔画人生2 小时前
Cursor + 蓝耘API:用自然语言完成全栈项目开发
前端·后端
有来技术3 小时前
ASP.NET Core 权限管理系统(RBAC)设计与实现|vue3-element-admin .NET 后端
vue.js·后端·c#·asp.net·.net
qq_12498707533 小时前
基于springboot的林业资源管理系统设计与实现(源码+论文+部署+安装)
java·vue.js·spring boot·后端·spring·毕业设计·计算机毕业设计
shuair3 小时前
springboot整合redisson单机模式
java·spring boot·后端
qq_12498707534 小时前
基于springboot的竞赛团队组建与管理系统的设计与实现(源码+论文+部署+安装)
java·vue.js·spring boot·后端·信息可视化·毕业设计·计算机毕业设计
Dr.Kun4 小时前
【鲲码园PsychoPy】Go/No-go范式
开发语言·后端·golang