ATG中的定时Job处理
一、ATG中定时Job核心处理Module
在ATG中核心的定时Job管理是放在Schedule这个Module下的,所以如果想要在你的应用拥有定时执行Job的能力,必须要在打包脚本中包含ScheduleModule。但是在生产环境中更为常见的做法是将ScheduleModule单独打包成为一个应用放在单独的Server实例上,其他的应用对其访问来触发相应的定时Job。这样做的好处是方便管理,也可以在一定程度上避免共享资源冲突。
二、ATG定时Job的几个概念:
1、Scheduler组件:shcedule模块的核心服务是/atg/dynamo/service/Scheduler组件,该组件负责所有Job的跟踪和触发。该组件的addScheduledJob方法接收一个ScheduledJob结构,来实现对定时Job的注册。
2、ScheduledJob结构:包含了Scheduler所需要所有参数选线的结构类。可参见下文代码。
3、Job组件:需要开发者自定义的组件,一个实现了atg.service.scheduler.Schedulable接口的组件。所有要做的工作都可以放在performScheduledTask实现。
调用/atg/dynamo/service/Scheduler组件的addScheduledJob方法 ,即可将一个Job组件加入到Scheduler中去实现定时触发
以下这段代码示例:一个Job组件包装为ScheduledJob结构传给Scheduler。
ScheduledJob job = new ScheduledJob ("hello", "Prints Hello", getAbsoluteName (), getSchedule (), ScheduleComponet, ScheduledJob.SCHEDULER_THREAD); jobId = getScheduler ().addScheduledJob (job);
注:这一段通常写在Job组件的doStartService方法中(需继承atg.nucleus.GenericService类),用于启动组件时即可定时触发。
4、Task:Job在执行过程中产生的实例,每次触发都会产生一个Task。
Task根据运行线程的位置不同有几种运行模式
(a)SCHEDULER_THREAD:在Scheduler的主线程上直接执行。在执行的过程中其他的定时任务无法执行。因此只适用于耗时较短的Task.
(b)SEPARATE_THREAD:另起一个单独的线程,线程结束后立即销毁。比较适用于那些定时间隔小于完成时间耗时的任务。例如完成一个任务大约需要5分钟。定时间隔设置为3分钟启动一次。
(c)REUSED_THREAD:另起一个单独的线程,任务结束后,任务挂起等待下一次调用。如果任务还在执行过程中,下一次调用又被触发。此时不会新建单独线程。
运行模式是在将job加入Scheduler时传入的,上文代码中ScheduledJob.SCHEDULER_THREAD即是此选项。
5、Schedule :对于定时任务执行时间的描述,即上文代码中的getSchedule ()返回的字符串。ATG中有两种定时方式
(a)按时间间隔:示例如下
schedule=in 30 seconds//在30秒之内执行一次 schedule=every 20 minutes//每20分钟执行一次(b)按照固定时间:ATG使用以空格分隔的字符串(共计6个描述单位)来表示月、日期、周、每月的第几周、小时、分钟。ATG官方文档对此描述的比较细致,不赘述。只举例如下
schedule=calendar 5 . 2 * * 0//Every Monday in June, every hour on the hour schedule=calendar * * * * 9-17 30//Every day, between 9am-5pm on the half hour
三、实践篇
1、写一个HelloJob.java类
import atg.nucleus.*; import atg.service.scheduler.*; public class HelloJob extends GenericService implements Schedulable { public HelloJob () {} // Scheduler property Scheduler scheduler; public Scheduler getScheduler () { return scheduler; } public void setScheduler (Scheduler scheduler) { this.scheduler = scheduler; } // Schedule property Schedule schedule; public Schedule getSchedule () { return schedule; } public void setSchedule (Schedule schedule) { this.schedule = schedule; } // Schedulable method public void performScheduledTask (Scheduler scheduler, ScheduledJob job) { System.out.println ("Hello"); } // Start method int jobId; public void doStartService () throws ServiceException { ScheduledJob job = new ScheduledJob ("hello", "Prints Hello", getAbsoluteName (), getSchedule (), this, ScheduledJob.SCHEDULER_THREAD); jobId = getScheduler ().addScheduledJob (job); } // Stop method public void doStopService () throws ServiceException { getScheduler ().removeScheduledJob (jobId); } }
2、定义helloJob的配置文件,形成组件
$class=HelloJob
$scope=global
scheduler=/atg/dynamo/service/Scheduler
schedule=every 1 minutes
3、定义该Job的启动时机
如果选择随Server启动即启动,则需要找到你应用的Initial.properties(如果没有在你的$ATG_INSTALL_DIR/home/localconfig可以创建一个),文件内容如下:
initialServices+=/test/HelloJob
注:如果采用按钮调用或者其他条件下启动,则需要根据自己的需求来使用代码控制何时触发该Job的注册。
4、打包、启动你的应用
5、访问dyn/admin应用,搜索/atg/dynamo/service/Scheduler即可看到所有Job,其中包含HelloJob
四、关于远程调用及SingletonSchedulableService
1、服务器间通信
ATG的应用是多个Module打包成为一个应用,一个应用独占为一个Server实例。原则上,ATG系统中每个应用都可以存在定时Job处理。但是通常情况下,生产环境只会存在一个Schedule服务实例,所有的定时任务都在这个实例上运行,因此很多情况下需要考虑服务间通信的问题。举例来说如果Store应用在用户下单后需要触发一个定时Job来完成某项工作,此时Store服务需要将此项Job注册到Schedule服务上,需要使用远程调用的方式实现,所以开发者在开发时需要明晰各种情况下的调用方式。当然远程调用是另外一个话题,之后再写文探讨。
2、SingletonSchedulableService
继承SingletonSchedulableService 类可以使用ATG提供的定时Job处理单例模式。此单例不是指当前应用下的单例,而是指ATG应用集群下单例模式。这样可以有效的避免多个应用都存在相同的定时job,导致资源冲突。具体细节可参考ATG官方文档。
3、其他
关于定时处理的官方文档可参照:http://docs.oracle.com/cd/E23095_01/Platform.93/ATGProgGuide/html/s0905schedulerservices01.html