Scheduler In Liferay 7.1/DXP
March 12, 2019
Introduction
Often, We have requirements to automate certain process and execute it on regular interval i.e send audit report after every week, send monthly newsletters etc. Scheduler programming helps us with all such requirement. Schedulers are the process which triggers certain logic after every specified interval. Liferay provides a flexible way to implement that. Today I’ll show you how you can implement scheduler in Liferay 7.1/DXP portal.
Step 1: Select StorageType of your scheduler
- The First thing you need to decide is the storageType which you are going to select for your scheduler. Liferay supports 3 StorageTypes:
1. StorageType.MEMORY_CLUSTERED
- This is the default storageType. It combines two aspects: MEMORY and CLUSTERED. For MEMORY, that means job details are stored in memory and for CLUSTERED, that means the job is aware of clustering and will only run on one node in the cluster.
2. StorageType.MEMORY
- This is the storageType where job information is stored in memory so you may miss running some jobs in case of outages. For example, If you have a job to run at 2’o clock and at that time suppose if your server is down due to some reason then your job will be missed.
3. StorageType.PERSISTED
- This storageType is the opposite of MEMORY where job details are persisted in database. So here for the missed jobs, when the server comes up, it will realize that job was missed and will immediately process the job.
Step 2: Create a Scheduler Class
- Create a scheduler class and extend BaseMessageListener class. You need to define a property called cron.experssion. Scheduler class is called based on this property value. Note that cron expressions are always based on the timezone of your app server. You can find more information about cron expressions here. http://www.quartz-scheduler.org/documentation/quartz-1.x/tutorials/crontrigger
@Component(
immediate = true,
property = {"cron.expression=0 0 14 * * ?"}, // Scheduler run daily at 2PM
service = SampleScheduler.class
)
public class SampleScheduler extends BaseMessageListener {
}
Step 3: Override Unimplemented Method
- In your custom scheduler class, you need to override doReceive method. In which you can add your custom code which executes every time when your scheduler is called.
- In this example, it will merely contain a statement that prints a simple message.
@Override
protected void doReceive(Message message) throws Exception {
LOG.info("Scheduled task executed...");
}
Step 4: Register The Scheduler
- This method is called whenever OSGi is activating the component. Here it will register the scheduler based on defined cron expressions.
@Activate
@Modified
protected void activate(Map<String,Object> properties) throws SchedulerException {
try {
// extract the cron expression from the properties
String cronExpression = GetterUtil.getString(properties.get("cron.expression"), _DEFAULT_CRON_EXPRESSION);
LOG.info(" cronExpression: " + cronExpression);
// create a new trigger definition for the job.
String listenerClass = getClass().getName();
Trigger jobTrigger = _triggerFactory.createTrigger(listenerClass, listenerClass, new Date(), null, cronExpression);
// wrap the current scheduler entry in our new wrapper.
// use the persisted storage type and set the wrapper back to the class field.
_schedulerEntryImpl = new SchedulerEntryImpl();
_schedulerEntryImpl = new StorageTypeAwareSchedulerEntryImpl(_schedulerEntryImpl, STORAGE_TYPE);
_schedulerEntryImpl.setEventListenerClass(listenerClass);
_schedulerEntryImpl.setTrigger(jobTrigger);
// update the trigger for the scheduled job.
//_schedulerEntryImpl.setTrigger(jobTrigger);
// if we were initialized (i.e. if this is called due to CA modification)
if (_initialized) {
// first deactivate the current job before we schedule.
deactivate();
}
// register the scheduled task
_schedulerEngineHelper.register(this, _schedulerEntryImpl, DestinationNames.SCHEDULER_DISPATCH);
// set the initialized flag.
_initialized = true;
} catch (Exception e){
LOG.error(e);
}
}
Step 5: Deactivate Scheduler
- You need to deactivate your scheduler at the time when OSGi is deactivating the component.
@Deactivate
protected void deactivate() {
// if we previously were initialized
if (_initialized) {
// unschedule the job so it is cleaned up
try {
_schedulerEngineHelper.unschedule(_schedulerEntryImpl, STORAGE_TYPE);
} catch (SchedulerException se) {
if (LOG.isWarnEnabled()) {
LOG.warn("Unable to unschedule trigger", se);
}
}
// unregister this listener
_schedulerEngineHelper.unregister(this);
}
// clear the initialized flag
_initialized = false;
}
That’s it using the above code you will be able to create your custom scheduler. Happy coding.