• quartz的使用(二.基本过程)


    1.关于各个要素的创建,SchedulerFactoryBean,CronTriggerFactoryBean及JobDetailFactoryBean全部实现spring中的FactoryBean<CronTrigger>, BeanNameAware, InitializingBean用于生成各自的实例

    1.1.JobDetailFactoryBean 使用JobDetail的实现类JobDetailImpl生成JobDetail实例

    public void afterPropertiesSet() {
                    if (this.name == null) {
                        this.name = this.beanName;
                    }
                    if (this.group == null) {
                        this.group = Scheduler.DEFAULT_GROUP;
                    }
                    if (this.applicationContextJobDataKey != null) {
                        if (this.applicationContext == null) {
                            throw new IllegalStateException(
                                "JobDetailBean needs to be set up in an ApplicationContext " +
                                "to be able to handle an 'applicationContextJobDataKey'");
                        }
                        getJobDataMap().put(this.applicationContextJobDataKey, this.applicationContext);
                    }
    
                    JobDetailImpl jdi = new JobDetailImpl();
                    jdi.setName(this.name);
                    jdi.setGroup(this.group);
                    jdi.setJobClass((Class) this.jobClass);
                    jdi.setJobDataMap(this.jobDataMap);
                    jdi.setDurability(this.durability);
                    jdi.setRequestsRecovery(this.requestsRecovery);
                    jdi.setDescription(this.description);
                    this.jobDetail = jdi;
                }

    1.2.CronTriggerFactoryBean使用Trigger的实现类CronTriggerImpl生成Trigger实例

    public void afterPropertiesSet() throws ParseException {
                    if (this.name == null) {
                        this.name = this.beanName;
                    }
                    if (this.group == null) {
                        this.group = Scheduler.DEFAULT_GROUP;
                    }
                    if (this.jobDetail != null) {
                        this.jobDataMap.put("jobDetail", this.jobDetail);
                    }
                    if (this.startDelay > 0 || this.startTime == null) {
                        this.startTime = new Date(System.currentTimeMillis() + this.startDelay);
                    }
                    if (this.timeZone == null) {
                        this.timeZone = TimeZone.getDefault();
                    }
    
                    CronTriggerImpl cti = new CronTriggerImpl();
                    cti.setName(this.name);
                    cti.setGroup(this.group);
                    if (this.jobDetail != null) {
                        cti.setJobKey(this.jobDetail.getKey());
                    }
                    cti.setJobDataMap(this.jobDataMap);
                    cti.setStartTime(this.startTime);
                    cti.setCronExpression(this.cronExpression);
                    cti.setTimeZone(this.timeZone);
                    cti.setCalendarName(this.calendarName);
                    cti.setPriority(this.priority);
                    cti.setMisfireInstruction(this.misfireInstruction);
                    cti.setDescription(this.description);
                    this.cronTrigger = cti;
                }

    1.3.SchedulerFactoryBean 使用StdSchedulerFacotory(通过配置文件来设置Scheduler的各项参数,还有一种DirectSchedulerFactory主要通过硬编码的不做介绍)
    创建Scheduler的实现StdScheduler,然后将所有功能托管给QuartzScheduler,实际所有功能通过QuartzScheduler实例进行实现

    public void afterPropertiesSet() throws Exception {
                    ...
    
                    // Create SchedulerFactory instance...
                    SchedulerFactory schedulerFactory = BeanUtils.instantiateClass(this.schedulerFactoryClass);
                    initSchedulerFactory(schedulerFactory);
    
                    ...
    
                    // Get Scheduler instance from SchedulerFactory.
                    try {
                        this.scheduler = createScheduler(schedulerFactory, this.schedulerName);
                        populateSchedulerContext();
    
                        if (!this.jobFactorySet && !(this.scheduler instanceof RemoteScheduler)) {
                            // Use AdaptableJobFactory as default for a local Scheduler, unless when
                            // explicitly given a null value through the "jobFactory" bean property.
                            this.jobFactory = new AdaptableJobFactory();
                        }
                        if (this.jobFactory != null) {
                            if (this.jobFactory instanceof SchedulerContextAware) {
                                ((SchedulerContextAware) this.jobFactory).setSchedulerContext(this.scheduler.getContext());
                            }
                            this.scheduler.setJobFactory(this.jobFactory);
                        }
                    }
    
                    ...

              //注册监听
              registerListeners();
              //注册job和trigger(更新或插入数据库)
              registerJobsAndTriggers();

    
                }

    1.4 启动QuartzScheduler.start(),通过spring的AbstractApplicationContext中的refresh()方法启动

     2.任务运行过程

     2.1创建QuartzScheduler时创建调度器主线程并运行

    public QuartzScheduler(QuartzSchedulerResources resources, long idleWaitTime, @Deprecated long dbRetryInterval)
                    throws SchedulerException {
                    
                    ....
    
                    this.schedThread = new QuartzSchedulerThread(this, resources);
                    ThreadExecutor schedThreadExecutor = resources.getThreadExecutor();
                    schedThreadExecutor.execute(this.schedThread);
                    
                    ...
                }

    2.2 QuartzSchedulerThread运行

    public void run() {
                    boolean lastAcquireFailed = false;
    
                    while (!halted.get()) {
                        try {
                            // check if we're supposed to pause...
                            synchronized (sigLock) {
                                while (paused && !halted.get()) {
                                    try {
                                        //等待直到togglePause(false)被调用,在QuartzScheduler.start()调用以后
                                        sigLock.wait(1000L);
                                    } catch (InterruptedException ignore) {
                                    }
                                }
    
                                if (halted.get()) {
                                    break;
                                }
                            }
                            //获取可用线程的数量,获取线程池,没有可用线程时等待
                            int availThreadCount = qsRsrcs.getThreadPool().blockForAvailableThreads();
                            if(availThreadCount > 0) { // will always be true, due to semantics of blockForAvailableThreads...
    
                                List<OperableTrigger> triggers = null;
    
                                long now = System.currentTimeMillis();
    
                                clearSignaledSchedulingChange();
                                try {
                                    //1.从jobStore中获取下次要触发的触发器集合//idleWaitTime == 30L * 1000L; 当调度程序发现没有当前触发器要触发,它应该等待多长时间再检查
                                    triggers = qsRsrcs.getJobStore().acquireNextTriggers(
                                            now + idleWaitTime, Math.min(availThreadCount, qsRsrcs.getMaxBatchSize()), qsRsrcs.getBatchTimeWindow());
                                    lastAcquireFailed = false;
                                    if (log.isDebugEnabled()) 
                                        log.debug("batch acquisition of " + (triggers == null ? 0 : triggers.size()) + " triggers");
                                } catch (JobPersistenceException jpe) {
                                    if(!lastAcquireFailed) {
                                        qs.notifySchedulerListenersError(
                                            "An error occurred while scanning for the next triggers to fire.",
                                            jpe);
                                    }
                                    lastAcquireFailed = true;
                                    continue;
                                } catch (RuntimeException e) {
                                    if(!lastAcquireFailed) {
                                        getLog().error("quartzSchedulerThreadLoop: RuntimeException "
                                                +e.getMessage(), e);
                                    }
                                    lastAcquireFailed = true;
                                    continue;
                                }
                                //若查询出触发器,则进行触发
                                if (triggers != null && !triggers.isEmpty()) {
    
                                    now = System.currentTimeMillis();
                                    long triggerTime = triggers.get(0).getNextFireTime().getTime();
                                    long timeUntilTrigger = triggerTime - now;
                                    //循环直至距离触发时间前2毫秒
                                    while(timeUntilTrigger > 2) {
                                        synchronized (sigLock) {
                                            if (halted.get()) {
                                                break;
                                            }
                                            if (!isCandidateNewTimeEarlierWithinReason(triggerTime, false)) {
                                                try {
                                                    // we could have blocked a long while
                                                    // on 'synchronize', so we must recompute
                                                    now = System.currentTimeMillis();
                                                    timeUntilTrigger = triggerTime - now;
                                                    if(timeUntilTrigger >= 1)
                                                        sigLock.wait(timeUntilTrigger);
                                                } catch (InterruptedException ignore) {
                                                }
                                            }
                                        }
                                        if(releaseIfScheduleChangedSignificantly(triggers, triggerTime)) {
                                            break;
                                        }
                                        now = System.currentTimeMillis();
                                        timeUntilTrigger = triggerTime - now;
                                    }
    
                                    // this happens if releaseIfScheduleChangedSignificantly decided to release triggers
                                    if(triggers.isEmpty())
                                        continue;
    
                                    // set triggers to 'executing'
                                    List<TriggerFiredResult> bndles = new ArrayList<TriggerFiredResult>();
    
                                    boolean goAhead = true;
                                    synchronized(sigLock) {
                                        goAhead = !halted.get();
                                    }
                                    if(goAhead) {
                                        try {
                                            //2.通知JobStore触发,其中加锁,更改状态
                                            List<TriggerFiredResult> res = qsRsrcs.getJobStore().triggersFired(triggers);
                                            if(res != null)
                                                //返回的数据赋值到bndles
                                                bndles = res;
                                        } catch (SchedulerException se) {
                                            qs.notifySchedulerListenersError(
                                                    "An error occurred while firing triggers '"
                                                            + triggers + "'", se);
                                            //QTZ-179 : a problem occurred interacting with the triggers from the db
                                            //we release them and loop again
                                            for (int i = 0; i < triggers.size(); i++) {
                                                //异常时,下同 数据库中ACQUIRED状态更新回WAITING后下次循环
                                                qsRsrcs.getJobStore().releaseAcquiredTrigger(triggers.get(i));
                                            }
                                            continue;
                                        }
    
                                    }
                                    //数据库关于quartz的表全部设置完成
                                    for (int i = 0; i < bndles.size(); i++) {
                                        TriggerFiredResult result =  bndles.get(i);
                                        TriggerFiredBundle bndle =  result.getTriggerFiredBundle();
                                        Exception exception = result.getException();
    
                                        if (exception instanceof RuntimeException) {
                                            getLog().error("RuntimeException while firing trigger " + triggers.get(i), exception);
                                            
                                            qsRsrcs.getJobStore().releaseAcquiredTrigger(triggers.get(i));
                                            continue;
                                        }
    
                                        // it's possible to get 'null' if the triggers was paused,
                                        // blocked, or other similar occurrences that prevent it being
                                        // fired at this time...  or if the scheduler was shutdown (halted)
                                        if (bndle == null) {
                                            
                                            qsRsrcs.getJobStore().releaseAcquiredTrigger(triggers.get(i));
                                            continue;
                                        }
    
                                        JobRunShell shell = null;
                                        try {
                                            //3.创建JobRunShell并初始化
                                            shell = qsRsrcs.getJobRunShellFactory().createJobRunShell(bndle);
                                            shell.initialize(qs);
                                        } catch (SchedulerException se) {
                                            qsRsrcs.getJobStore().triggeredJobComplete(triggers.get(i), bndle.getJobDetail(), CompletedExecutionInstruction.SET_ALL_JOB_TRIGGERS_ERROR);
                                            continue;
                                        }
                                        //交由线程池处理任务
                                        if (qsRsrcs.getThreadPool().runInThread(shell) == false) {
                                            // this case should never happen, as it is indicative of the
                                            // scheduler being shutdown or a bug in the thread pool or
                                            // a thread pool being used concurrently - which the docs
                                            // say not to do...调度程序正在关闭或线程池或线程池中并发使用的错误
                                            getLog().error("ThreadPool.runInThread() return false!");
                                            qsRsrcs.getJobStore().triggeredJobComplete(triggers.get(i), bndle.getJobDetail(), CompletedExecutionInstruction.SET_ALL_JOB_TRIGGERS_ERROR);
                                        }
    
                                    }
    
                                    continue; // while (!halted)
                                }
                            } else { // if(availThreadCount > 0)
                                // should never happen, if threadPool.blockForAvailableThreads() follows contract
                                continue; // while (!halted)
                            }
                            //在最后调度线程生成了一个随机的等待时间,进入短暂的等待,这使得其他节点的调度器都有机会获取数据库资源.如此就实现了quratz的负载平衡
                            long now = System.currentTimeMillis();
                            long waitTime = now + getRandomizedIdleWaitTime();
                            long timeUntilContinue = waitTime - now;
                            synchronized(sigLock) {
                                try {
                                  if(!halted.get()) {
                                    // QTZ-336 A job might have been completed in the mean time and we might have
                                    // missed the scheduled changed signal by not waiting for the notify() yet
                                    // Check that before waiting for too long in case this very job needs to be
                                    // scheduled very soon
                                    if (!isScheduleChanged()) {
                                      sigLock.wait(timeUntilContinue);
                                    }
                                  }
                                } catch (InterruptedException ignore) {
                                }
                            }
    
                        } catch(RuntimeException re) {
                            getLog().error("Runtime error occurred in main trigger firing loop.", re);
                        }
                    } // while (!halted)
    
                    // drop references to scheduler stuff to aid garbage collection...
                    qs = null;
                    qsRsrcs = null;
                }
    2.2.1.获取下次要触发的触发器集合

    过程为:获取待触发trigger-->数据库LOCKS表TRIGGER_ACCESS行加锁-->读取JobDetail信息-->读取trigger表中触发器信息并标记为"已获取"-->commit事务,释放锁

    public List<OperableTrigger> acquireNextTriggers(final long noLaterThan, final int maxCount, final long timeWindow)
                    throws JobPersistenceException {
                    
                    String lockName;
                    //isAcquireTriggersWithinLock()方法判断属性acquireTriggersWithinLock默认为false,maxCount默认=1故默认不加锁
                    //可以在配置文件中配置org.quartz.jobStore.acquireTriggersWithinLock=true使其每次获取时加锁
                    if(isAcquireTriggersWithinLock() || maxCount > 1) { 
                        lockName = LOCK_TRIGGER_ACCESS;
                    } else {
                        lockName = null;
                    }
                    return executeInNonManagedTXLock(lockName, 
                            new TransactionCallback<List<OperableTrigger>>() {
                                public List<OperableTrigger> execute(Connection conn) throws JobPersistenceException {
                                    //返回下次需要执行的trigger
                                    return acquireNextTrigger(conn, noLaterThan, maxCount, timeWindow);
                                }
                            },
                            new TransactionValidator<List<OperableTrigger>>() {
                                public Boolean validate(Connection conn, List<OperableTrigger> result) throws JobPersistenceException {
                                    try {
                                        List<FiredTriggerRecord> acquired = getDelegate().selectInstancesFiredTriggerRecords(conn, getInstanceId());
                                        Set<String> fireInstanceIds = new HashSet<String>();
                                        for (FiredTriggerRecord ft : acquired) {
                                            fireInstanceIds.add(ft.getFireInstanceId());
                                        }
                                        for (OperableTrigger tr : result) {
                                            if (fireInstanceIds.contains(tr.getFireInstanceId())) {
                                                return true;
                                            }
                                        }
                                        return false;
                                    } catch (SQLException e) {
                                        throw new JobPersistenceException("error validating trigger acquisition", e);
                                    }
                                }
                            });
                }
    protected List<OperableTrigger> acquireNextTrigger(Connection conn, long noLaterThan, int maxCount, long timeWindow)
                    throws JobPersistenceException {
                    if (timeWindow < 0) {
                      throw new IllegalArgumentException();
                    }
                    
                    List<OperableTrigger> acquiredTriggers = new ArrayList<OperableTrigger>();
                    Set<JobKey> acquiredJobKeysForNoConcurrentExec = new HashSet<JobKey>();
                    final int MAX_DO_LOOP_RETRY = 3;
                    int currentLoopCount = 0;
                    do {
                        currentLoopCount ++;
                        try {
                            //sql为:SELECT TRIGGER_NAME, TRIGGER_GROUP, NEXT_FIRE_TIME, PRIORITY FROM {0}TRIGGERS 
                            //WHERE SCHED_NAME = {1} AND TRIGGER_STATE = ? AND NEXT_FIRE_TIME <= ? AND (MISFIRE_INSTR = -1 OR (MISFIRE_INSTR != -1 AND NEXT_FIRE_TIME >= ?)) ORDER BY NEXT_FIRE_TIME ASC, PRIORITY DESC
                            List<TriggerKey> keys = getDelegate().selectTriggerToAcquire(conn, noLaterThan + timeWindow, getMisfireTime(), maxCount);
                            
                            // No trigger is ready to fire yet.
                            if (keys == null || keys.size() == 0)
                                return acquiredTriggers;
    
                            long batchEnd = noLaterThan;
    
                            for(TriggerKey triggerKey: keys) {
                                // If our trigger is no longer available, try a new one.
                                //sql:SELECT * FROM {0}TRIGGERS WHERE SCHED_NAME = {1} AND TRIGGER_NAME = ? AND TRIGGER_GROUP = ?
                                OperableTrigger nextTrigger = retrieveTrigger(conn, triggerKey);
                                if(nextTrigger == null) {
                                    continue; // next trigger
                                }
                                
                                // If trigger's job is set as @DisallowConcurrentExecution, and it has already been added to result, then
                                // put it back into the timeTriggers set and continue to search for next trigger.
                                
                                JobKey jobKey = nextTrigger.getJobKey();
                                JobDetail job;
                                try {
                                    //sql:SELECT * FROM {0}JOB_DETAILS WHERE SCHED_NAME = {1} AND JOB_NAME = ? AND JOB_GROUP = ?
                                    job = retrieveJob(conn, jobKey);
                                } catch (JobPersistenceException jpe) {
                                    try {
                                        getLog().error("Error retrieving job, setting trigger state to ERROR.", jpe);
                                        getDelegate().updateTriggerState(conn, triggerKey, STATE_ERROR);
                                    } catch (SQLException sqle) {
                                        getLog().error("Unable to set trigger state to ERROR.", sqle);
                                    }
                                    continue;
                                }
                                //(有状态任务,类上是否加上注解@DisallowConcurrentExecution或实现StatefulJob,任务执行时间过长,下一次任务时间开始则阻塞不触发)
                                if (job.isConcurrentExectionDisallowed()) {
                                    //若已经存在则跳过
                                    if (acquiredJobKeysForNoConcurrentExec.contains(jobKey)) {
                                        continue; // next trigger
                                    } else {
                                        acquiredJobKeysForNoConcurrentExec.add(jobKey);
                                    }
                                }
                                
                                if (nextTrigger.getNextFireTime().getTime() > batchEnd) {
                                  break;
                                }
                                // We now have a acquired trigger, let's add to return list.
                                // If our trigger was no longer in the expected state, try a new one.
                                //将查询出的WAITING状态的trigger更新为ACQUIRED
                                //sql:UPDATE {0}TRIGGERS SET TRIGGER_STATE = ? WHERE SCHED_NAME = {1} AND TRIGGER_NAME = ? AND TRIGGER_GROUP = ? AND TRIGGER_STATE = ?
                                int rowsUpdated = getDelegate().updateTriggerStateFromOtherState(conn, triggerKey, STATE_ACQUIRED, STATE_WAITING);
                                if (rowsUpdated <= 0) {
                                    continue; // next trigger
                                }
                                nextTrigger.setFireInstanceId(getFiredTriggerRecordId());
                                //sql:INSERT INTO {0}FIRED_TRIGGERS (SCHED_NAME, ENTRY_ID, TRIGGER_NAME, TRIGGER_GROUP, INSTANCE_NAME, FIRED_TIME, SCHED_TIME, STATE, JOB_NAME, JOB_GROUP, IS_NONCONCURRENT, REQUESTS_RECOVERY, PRIORITY) 
                                //VALUES({1}, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
                            
                                getDelegate().insertFiredTrigger(conn, nextTrigger, STATE_ACQUIRED, null);
    
                                if(acquiredTriggers.isEmpty()) {
                                    batchEnd = Math.max(nextTrigger.getNextFireTime().getTime(), System.currentTimeMillis()) + timeWindow;
                                }
                                //下次执行的Trigger放入acquiredTriggers List中 
                                acquiredTriggers.add(nextTrigger);
                            }
    
                            // if we didn't end up with any trigger to fire from that first
                            // batch, try again for another batch. We allow with a max retry count.
                            //如果为空,可以循环3次
                            if(acquiredTriggers.size() == 0 && currentLoopCount < MAX_DO_LOOP_RETRY) {
                                continue;
                            }
                            
                            // We are done with the while loop.
                            break;
                        } catch (Exception e) {
                            throw new JobPersistenceException(
                                      "Couldn't acquire next trigger: " + e.getMessage(), e);
                        }
                    } while (true);
                    
                    // Return the acquired trigger list
                    return acquiredTriggers;
                }
    2.2.2.触发trigger

    执行过程与上述过程类似,此时是必定加锁的:数据库LOCKS表STATE_ACCESS行加锁-->确认trigger的状态-->读取trigger的JobDetail信息-->读取trigger的Calendar信息-->更新trigger信息-->commit事务,释放锁

    public List<TriggerFiredResult> triggersFired(final List<OperableTrigger> triggers) throws JobPersistenceException {
                    return executeInNonManagedTXLock(LOCK_TRIGGER_ACCESS,
                            new TransactionCallback<List<TriggerFiredResult>>() {
                                public List<TriggerFiredResult> execute(Connection conn) throws JobPersistenceException {
                                    List<TriggerFiredResult> results = new ArrayList<TriggerFiredResult>();
    
                                    TriggerFiredResult result;
                                    for (OperableTrigger trigger : triggers) {
                                        try {
                                            //主要方法
                                          TriggerFiredBundle bundle = triggerFired(conn, trigger);
                                          result = new TriggerFiredResult(bundle);
                                        } catch (JobPersistenceException jpe) {
                                            result = new TriggerFiredResult(jpe);
                                        } catch(RuntimeException re) {
                                            result = new TriggerFiredResult(re);
                                        }
                                        results.add(result);
                                    }
    
                                    return results;
                                }
                            },
                            new TransactionValidator<List<TriggerFiredResult>>() {
                                @Override
                                public Boolean validate(Connection conn, List<TriggerFiredResult> result) throws JobPersistenceException {
                                    try {
                                        List<FiredTriggerRecord> acquired = getDelegate().selectInstancesFiredTriggerRecords(conn, getInstanceId());
                                        Set<String> executingTriggers = new HashSet<String>();
                                        for (FiredTriggerRecord ft : acquired) {
                                            if (STATE_EXECUTING.equals(ft.getFireInstanceState())) {
                                                executingTriggers.add(ft.getFireInstanceId());
                                            }
                                        }
                                        for (TriggerFiredResult tr : result) {
                                            if (tr.getTriggerFiredBundle() != null && executingTriggers.contains(tr.getTriggerFiredBundle().getTrigger().getFireInstanceId())) {
                                                return true;
                                            }
                                        }
                                        return false;
                                    } catch (SQLException e) {
                                        throw new JobPersistenceException("error validating trigger acquisition", e);
                                    }
                                }
                            });
                }
    protected TriggerFiredBundle triggerFired(Connection conn,
                OperableTrigger trigger)
                    throws JobPersistenceException {
                    JobDetail job;
                    Calendar cal = null;
    
                    // Make sure trigger wasn't deleted, paused, or completed...
                    try { // if trigger was deleted, state will be STATE_DELETED
                        //查询状态,不为触发状态则跳过
                        //sql:SELECT TRIGGER_STATE FROM {0}TRIGGERS WHERE SCHED_NAME = {1} AND TRIGGER_NAME = ? AND TRIGGER_GROUP = ?
                        String state = getDelegate().selectTriggerState(conn,
                                trigger.getKey());
                        if (!state.equals(STATE_ACQUIRED)) {
                            return null;
                        }
                    } catch (SQLException e) {
                        throw new JobPersistenceException("Couldn't select trigger state: "
                                + e.getMessage(), e);
                    }
    
                    try {
                        //sql:SELECT * FROM {0}JOB_DETAILS WHERE SCHED_NAME = {1} AND JOB_NAME = ? AND JOB_GROUP = ?
                        job = retrieveJob(conn, trigger.getJobKey());
                        if (job == null) { return null; }
                    } catch (JobPersistenceException jpe) {
                        try {
                            getLog().error("Error retrieving job, setting trigger state to ERROR.", jpe);
                            getDelegate().updateTriggerState(conn, trigger.getKey(),
                                    STATE_ERROR);
                        } catch (SQLException sqle) {
                            getLog().error("Unable to set trigger state to ERROR.", sqle);
                        }
                        throw jpe;
                    }
                    //若有设置特殊的日期与cron关联
                    if (trigger.getCalendarName() != null) {
                        cal = retrieveCalendar(conn, trigger.getCalendarName());
                        if (cal == null) { return null; }
                    }
    
                    try {
                        //更新执行中trigger的信息
                        //sql:UPDATE {0}FIRED_TRIGGERS SET INSTANCE_NAME = ?, FIRED_TIME = ?, SCHED_TIME = ?, STATE = ?, JOB_NAME = ?, JOB_GROUP = ?, IS_NONCONCURRENT = ?, REQUESTS_RECOVERY = ? WHERE SCHED_NAME = {1} AND ENTRY_ID = ?
                        getDelegate().updateFiredTrigger(conn, trigger, STATE_EXECUTING, job);
                    } catch (SQLException e) {
                        throw new JobPersistenceException("Couldn't insert fired trigger: "
                                + e.getMessage(), e);
                    }
    
                    Date prevFireTime = trigger.getPreviousFireTime();
    
                    // call triggered - to update the trigger's next-fire-time state...
                    //更新触发器的下一个触发时间状态
                    //previousFireTime = nextFireTime;
                    //nextFireTime = getFireTimeAfter(nextFireTime);
                    trigger.triggered(cal);
    
                    String state = STATE_WAITING;
                    boolean force = true;
                    //任务是否是有状态的,若是,则将状态STATE_WAITING-->STATE_BLOCKED,STATE_ACQUIRED-->STATE_BLOCKED,STATE_PAUSED-->STATE_PAUSED_BLOCKED
                    if (job.isConcurrentExectionDisallowed()) {
                        state = STATE_BLOCKED;
                        force = false;
                        try {
                            getDelegate().updateTriggerStatesForJobFromOtherState(conn, job.getKey(),
                                    STATE_BLOCKED, STATE_WAITING);
                            getDelegate().updateTriggerStatesForJobFromOtherState(conn, job.getKey(),
                                    STATE_BLOCKED, STATE_ACQUIRED);
                            getDelegate().updateTriggerStatesForJobFromOtherState(conn, job.getKey(),
                                    STATE_PAUSED_BLOCKED, STATE_PAUSED);
                        } catch (SQLException e) {
                            throw new JobPersistenceException(
                                    "Couldn't update states of blocked triggers: "
                                            + e.getMessage(), e);
                        }
                    } 
                    //判断是否还有下次触发
                    if (trigger.getNextFireTime() == null) {
                        state = STATE_COMPLETE;
                        force = true;
                    }
                    //插入或更新trigger
                    storeTrigger(conn, trigger, job, true, state, force, false);
    
                    job.getJobDataMap().clearDirtyFlag();
                    //创建一个 TriggerFiredBundle的对象
                    return new TriggerFiredBundle(job, trigger, cal, trigger.getKey().getGroup()
                            .equals(Scheduler.DEFAULT_RECOVERY_GROUP), new Date(), trigger
                            .getPreviousFireTime(), prevFireTime, trigger.getNextFireTime());
                }
    2.2.3.实例化并执行Job

    为每个Job生成一个可运行的RunShell,并放入线程池运行

    public boolean runInThread(Runnable runnable) {
                    if (runnable == null) {
                        return false;
                    }
    
                    synchronized (nextRunnableLock) {
    
                        handoffPending = true;
    
                        // Wait until a worker thread is available
                        //直至线程池有可用线程
                        while ((availWorkers.size() < 1) && !isShutdown) {
                            try {
                                nextRunnableLock.wait(500);
                            } catch (InterruptedException ignore) {
                            }
                        }
    
                        if (!isShutdown) {
                            WorkerThread wt = (WorkerThread)availWorkers.removeFirst();
                            busyWorkers.add(wt);
                            wt.run(runnable);
                        } else {
                            // If the thread pool is going down, execute the Runnable
                            // within a new additional worker thread (no thread from the pool).
                            WorkerThread wt = new WorkerThread(this, threadGroup,
                                    "WorkerThread-LastJob", prio, isMakeThreadsDaemons(), runnable);
                            busyWorkers.add(wt);
                            workers.add(wt);
                            wt.start();
                        }
                        nextRunnableLock.notifyAll();
                        handoffPending = false;
                    }
    
                    return true;
                }
    public void run() {
                    qs.addInternalSchedulerListener(this);
    
                    try {
                        OperableTrigger trigger = (OperableTrigger) jec.getTrigger();
                        JobDetail jobDetail = jec.getJobDetail();
    
                        do {
    
                            JobExecutionException jobExEx = null;
                            Job job = jec.getJobInstance();
    
                            try {
                                begin();
                            } catch (SchedulerException se) {
                                qs.notifySchedulerListenersError("Error executing Job ("
                                        + jec.getJobDetail().getKey()
                                        + ": couldn't begin execution.", se);
                                break;
                            }
    
                            // notify job & trigger listeners...
                            try {
                                if (!notifyListenersBeginning(jec)) {
                                    break;
                                }
                            } catch(VetoedException ve) {
                                try {
                                    CompletedExecutionInstruction instCode = trigger.executionComplete(jec, null);
                                    qs.notifyJobStoreJobVetoed(trigger, jobDetail, instCode);
                                    
                                    // QTZ-205
                                    // Even if trigger got vetoed, we still needs to check to see if it's the trigger's finalized run or not.
                                    if (jec.getTrigger().getNextFireTime() == null) {
                                        qs.notifySchedulerListenersFinalized(jec.getTrigger());
                                    }
    
                                    complete(true);
                                } catch (SchedulerException se) {
                                    qs.notifySchedulerListenersError("Error during veto of Job ("
                                            + jec.getJobDetail().getKey()
                                            + ": couldn't finalize execution.", se);
                                }
                                break;
                            }
    
                            long startTime = System.currentTimeMillis();
                            long endTime = startTime;
    
                            // execute the job
                            try {
                                log.debug("Calling execute on job " + jobDetail.getKey());
                                //执行JOB的execute(),在测试中为QuartzJobBean的execute()其中会调用子类的executeInternal()方法
                                job.execute(jec);
                                endTime = System.currentTimeMillis();
                            } catch (JobExecutionException jee) {
                                //如果execute抛出异常,并且是JobExecutionException,JobExecutionException会保存着是重试,还是结束的信息
                                endTime = System.currentTimeMillis();
                                jobExEx = jee;
                                getLog().info("Job " + jobDetail.getKey() +
                                        " threw a JobExecutionException: ", jobExEx);
                            } catch (Throwable e) {
                                endTime = System.currentTimeMillis();
                                getLog().error("Job " + jobDetail.getKey() +
                                        " threw an unhandled Exception: ", e);
                                SchedulerException se = new SchedulerException(
                                        "Job threw an unhandled exception.", e);
                                qs.notifySchedulerListenersError("Job ("
                                        + jec.getJobDetail().getKey()
                                        + " threw an exception.", se);
                                jobExEx = new JobExecutionException(se, false);
                            }
    
                            jec.setJobRunTime(endTime - startTime);
    
                            // notify all job listeners
                            if (!notifyJobListenersComplete(jec, jobExEx)) {
                                break;
                            }
    
                            CompletedExecutionInstruction instCode = CompletedExecutionInstruction.NOOP;
    
                            // update the trigger
                            try {
                                //根据不同状态设置不同指令编码
                                instCode = trigger.executionComplete(jec, jobExEx);
                            } catch (Exception e) {
                                // If this happens, there's a bug in the trigger...
                                SchedulerException se = new SchedulerException(
                                        "Trigger threw an unhandled exception.", e);
                                qs.notifySchedulerListenersError(
                                        "Please report this error to the Quartz developers.",
                                        se);
                            }
    
                            // notify all trigger listeners
                            if (!notifyTriggerListenersComplete(jec, instCode)) {
                                break;
                            }
    
                            // update job/trigger or re-execute job
                            if (instCode == CompletedExecutionInstruction.RE_EXECUTE_JOB) {
                                jec.incrementRefireCount();
                                try {
                                    complete(false);
                                } catch (SchedulerException se) {
                                    qs.notifySchedulerListenersError("Error executing Job ("
                                            + jec.getJobDetail().getKey()
                                            + ": couldn't finalize execution.", se);
                                }
                                continue;
                            }
    
                            try {
                                complete(true);
                            } catch (SchedulerException se) {
                                qs.notifySchedulerListenersError("Error executing Job ("
                                        + jec.getJobDetail().getKey()
                                        + ": couldn't finalize execution.", se);
                                continue;
                            }
                            //任务完成,其方法中 根据instCode的值去更新不同的状态,若加入了注解@DisallowConcurrentExecution则将STATE_BLOCKED-->STATE_BLOCKED
                            //若加上@PersistJobDataAfterExecution,则将_job_details表中的jobMapData数据持久化用于下次执行共享
                            qs.notifyJobStoreJobComplete(trigger, jobDetail, instCode);
                            break;
                        } while (true);
    
                    } finally {
                        qs.removeInternalSchedulerListener(this);
                    }
                }
  • 相关阅读:
    camunda_07_gateways
    camunda_temp
    camunda_16_listener
    camunda_05_integrity_architect
    drools_10_function
    drools_05_query
    drools_09_drools_helper
    camunda_08_task_exception
    camunda_17_external_task
    带团队后的日常思考(十)
  • 原文地址:https://www.cnblogs.com/lantuanqing/p/10998079.html
Copyright © 2020-2023  润新知