Roller的任务调度设计探讨

 

背景

 

以前看过Roller的任务调度,最近需要用到。虽然任务调度这方面的第三方支持包不少,比如quartz,但也不想那么麻烦加入这么重量级的框架。也不知道为什么Roller的设计不用quartz之类的调度框架,也许Roller项目开始的quartz还没有成熟吧。这些就无法去管了,问题是Roller的任务调度如果不是经常使用,很快就忘记了,所以决定以本文记录一下,以后参考。

 

类图

 

 

TreadManager及其子类主要是初始化任务列表、启动任务调度器TaskScheduler、登记任务租期、解除租期。

 

TaskScheduler:主要管理任务调度,将加到其列表中的任务按照指定时间来启动。

 

RollerTask:定义了一系列的抽象方法,用于任务调度、运行期间操作。

 

RollerTaskWithLeasing 定义了一个执行具体任务的抽象方法,和实现run方法。主要是为了控制相同的任务不能在同一租期内执行。

 

TaskLock:一个记录任务的相关信息类,提供两个重要的方法:1、计算下次执行时间;2、计算任务执行完毕时间。

工作原理

 

Roller启动后,会初始化所有管理类,JPAThreadManagerImpl也在初始化之列。JPAThreadManagerImplinitialize被执行,此方法主要的逻辑有:

1、 读取配置文件,获得需要实例化的任务RollerTask类的子类,并实例化和初始化这些任务对象。

2、 如果这些任务没有加锁TaskLock,则新建一个锁,并保存到数据库中。

3、 将任务对象加入到任务列表中webloggerTasks

4、 将任务列表作为参数,创建一个任务调度器TaskScheduler

5、 将任务调度器TaskScheduler(通过类图可TaskSchedulerrunnable实现类)作为参数,创建一个线程并启动。

 

至此,JPAThreadManagerImpl初始化完成,控制权交给任务调度器TaskScheduler。在TaskSchedulerrun方法中有个while循环,此循环一直运行到Roller被停止,其主要目的是为了控制在任务列表webloggerTasks中的任务的调度。

 

过程如下:

1、 遍历所有任务列表中的RollerTask对象。

2、 取得RollerTask的锁TaskLock(初始化的时候已经加锁)。

3、 计算下次启动时间(通过TaskLockRollerTask的相关方法)。

4、 如果下次启动时间大于当前时间+1分钟

a)   如果是startOfDay,并且当前时间大于当天000 + 2分钟,继续等待;

b)   如果是startOfHour,并且当前时间大于当时00 + 2分钟,继续等待;

c)   如果是immediate,下一步。

 

5、 如果当前时间大于等于下次运行时间,并且第4步计算不需要等待,则将RollerTask提交到线程池被启动。

 

由于任务调度器TaskScheduler不断循环,所有加到任务列表里的任务都可能不止一次被启动,那么Roller是如何控制一个任务能被按指定的时间来启动的呢?除了前面的分析,后面还有一个任务的加锁解锁的过程。

 

RollerTask被放到线程池并且启动后,其抽象子类RollerTaskWithLeasingrun方法将被执行,run方法在这里是一个模板方法。通过前面的分析,我们知道任务调度器TaskScheduler在某个微小时段会多次启动同一个任务,那么如何控制一个已经被启动的任务在它未完成之前,相同的任务不能启动呢?run方法主要是解决这个问题,其主要逻辑是对此任务执行期间加锁,执行结束解锁。

 

run被执行时:

1、 登记租期,表示任务如果被执行,那么现在开始到什么时候结束。也就是加锁的意思,其他相同的任务不能在租期未结束之前执行。

这里有主要的逻辑要说明,先从数据库将任务的TaskLock信息读取出来,这些信息包括timeAquired(上次被读取的时间)、timeLeased(租期分钟)、最后一次执行时间等。然后通过timeAquiredtimeLeased来计算当前时间是否在上次执行租期后面。如果是在后面则表示这次登记租期成功。

 

具体技巧如下,如果能成功执行下面sql,表示登记成功。

<query> UPDATE TaskLock t SET t.clientId=?1, t.timeAquired= CURRENT_TIMESTAMP, t.timeLeased= ?2, t.lastRun= ?3 WHERE t.name=?4 AND t.timeAquired=?5 AND ?6 &lt; CURRENT_TIMESTAMP</query>

 

 

2、 如果登记租期成功,执行具体任务。

3、 注销租期,表示任务已经执行完毕,租期解除。

 

至此Roller任务调度管理整改流程大概是这样子。

 

注意事项

1、配置说明

# Tasks which are enabled.  Only tasks listed here will be run.

tasks.enabled=ScheduledEntriesTask,ResetHitCountsTask,TurnoverReferersTask,PingQueueTask

 

# client identifier.  should be unique for each instance in a cluster.

tasks.clientId=defaultClientId

 

# Publish scheduled weblog entries

tasks.ScheduledEntriesTask.class=org.apache.roller.weblogger.business.runnable.ScheduledEntriesTask

# 可以设置的值有:'immediate', 'startOfDay', 'startOfHour'

tasks.ScheduledEntriesTask.startTime=immediate   

# 表示两次任务执行的时间间隔,单位:分钟

tasks.ScheduledEntriesTask.interval=1

# 表示任务从开始执行到完毕需要的时间,单位:分钟

tasks.ScheduledEntriesTask.leaseTime=30

 

 

2实现类,建议拷贝RollerTaskWithLeasing的子类来修改即可。同时注意配置是要在tasks.enabled中添加类名。

猜你喜欢

转载自devroller2.iteye.com/blog/1319614