Scheduler is one of the important components in any application. To perform jobs periodically then application is required scheduler. Liferay portal is providing scheduler in portal and we can schedule jobs in portal applications.
Liferay implemented scheduler on top of the quartz scheduler engine. Quartz is popular open-source java implementation for scheduling jobs.
Liferay build another API on top native quartz so that we can easily configure or created schedule jobs in Liferay Portal Applications.
Software Stack
Liferay-ce-portal-7.4.1-ga2 |
Liferay Scheduler API is using Message Bus to delegate
job to backend process.
High-level scheduler implementation in Liferay
- Liferay provides scheduler API to create schedule job which is tagged to specific Message Bus destination.
- Each destination has one or more message listeners register with destination. Destination may be Parallel or Serial.
- Scheduler Engine will trigger Job at defined time frame based CRON expression.
- Job is responsible to send message (Delegate job) to Message Bus on specific destination and that was already configured as part of scheduling.
- Listener will receive the message which posted in Message Bus destination.
- Once Listener is received the message then process the message and execute the further steps.
All business logic will be implemented in the listener
so that it will be invoked when the message posted on the Message Bus. Sending message
to Message Bus is configured by schedule job and scheduler engine will trigger
job based on the cron expression. Message
Bus is really useful concept for scheduler to assign job in the blackened
process.
Example
Sending email to group of users periodically like daily/weekly/month.
Liferay is providing different job storage types while creating schedule job.
Memory
When we use single liferay instance environment then memory storage type can be useful and all scheduled jobs information is stored in portal memory. If server restarted all scheduled jobs information will be lost.
Memory Cluster
Memory Cluster is similar to memory storage type but this is being used in Clustered environment. If job created in one instance memory that will be replicated in other instance memory. There are chances of loss of schedule job details if the both instances are crash or down.
Persisted
Persisted storage is another available type storage and job data will be stored in the database quartz tables. So, when the scheduler engine stared then all jobs will be scheduled based on the information available in the database. There is no loss of scheduled job data.
The following are the QUARTZ tabled created by
Quartz scheduler during liferay startup.
When we create schedule job, we must select the storage
type so that job details will be stored in either memory or database tables.
Clustered environment, jobs may fire from multiple
instances so we have to be very careful. Quartz internally uses the locking
mechanism so that only one scheduler instance fires the job and other instances
never fire same job at same time.
The following is steps to create dynamic schedule jobs
- Create Destination
- Register Listener with Destination
- Add destination to Message Bus
- Create Scheduler job and tag to destination
Following is groovy code snipper to create schedule
job and tag to Message Bus destination. Here is using the existing Dummy
Message Listener to demonstrate the example. Usually, we will create our own
message listener and implement business login as part of message listener.
Below schedule job is for every minute and for every
minute scheduler engine post a message on Message Bus for specific destination
and dummy message listener receive the message and execute the received method
which prints the message object in logs.
Find script from below GitHub repository.
OR
import
com.liferay.portal.kernel.messaging.Destination; import com.liferay.portal.kernel.messaging.DestinationConfiguration; import
com.liferay.portal.kernel.messaging.DestinationFactoryUtil; import
com.liferay.portal.kernel.messaging.DummyMessageListener; import
com.liferay.portal.kernel.messaging.Message; import com.liferay.portal.kernel.messaging.MessageBusUtil; import
com.liferay.portal.kernel.messaging.MessageListener; import
com.liferay.portal.kernel.portlet.PortletClassLoaderUtil; import
com.liferay.portal.kernel.scheduler.SchedulerEngineHelperUtil; import com.liferay.portal.kernel.scheduler.StorageType; import
com.liferay.portal.kernel.scheduler.Trigger; import
com.liferay.portal.kernel.scheduler.TriggerFactoryUtil; import
com.liferay.portal.kernel.util.PortalClassLoaderUtil; String
destinationName = "liferaysavvy/parallel-destination"; String className
= DummyMessageListener.class.getName(); String jobName =
"com.liferay.portal.kernel.messaging.DummyMessageListener"; String groupName
= "com.liferay.portal.kernel.messaging.DummyMessageListener"; //Every minute String
cronExpression = "0 0/1 * * * ?"; String
description = "Every one minute job using Parallel Destination.."; int
exceptionsMaxSize = 10; //Create
destination and register listener try { DestinationConfiguration
destinationConfig = DestinationConfiguration.createParallelDestinationConfiguration(destinationName); Destination parallelDestination =
DestinationFactoryUtil.createDestination(destinationConfig); String portletId = null; ClassLoader classLoader = null; if(portletId != null){ //PortletClassLoaderUtil.setServletContextName(portletId); classLoader =
PortletClassLoaderUtil.getClassLoader(portletId); } else { classLoader =
PortalClassLoaderUtil.getClassLoader(); } MessageListener messageListener =
(MessageListener)classLoader.loadClass(className).newInstance(); out.println("messageListener ::
${messageListener}"); parallelDestination.register(messageListener); MessageBusUtil.addDestination(parallelDestination); //Create schedule job with cron
expression. Trigger trigger =
TriggerFactoryUtil.createTrigger(jobName,groupName,cronExpression); Message message = new Message(); message.put("data","My
Data required for job.."); SchedulerEngineHelperUtil.schedule(trigger,
StorageType.PERSISTED, description,destinationName, message,
exceptionsMaxSize) } catch
(Exception e) { e.printStackTrace(); } |
Global Menu --> Control Panel -->System -->Server Administration
Click on script, copy paste the above script in the
editor and execute it.
Schedule job will be created and job details is stored
in database.
We can see scheduled job details in the database
table.
Cron trigger table have details of Trigger
Verify Dummy Listener logs
Created schedule job for every minute so scheduler
engine will send message for every minute on given destination and Dummy
Listener will receive the message object.
Enable info logs for “com.liferay.portal.kernel.messaging.DummyMessageListener”
Global Menu --> Control Panel -->System -->Server Administration
Click on log Levels and Click on + Add Category
Provide logger name and Log levels as follows and save
details. Now dummy listener will show all logs in the console.
Open server logs console and we can observe that every
minute Dummy Message Listener is receiving message from Message Bus and print
the message object in the logs.
This is how Liferay scheduler works and it used Native
Quartz and Message Bus.
Following is sample groovy script to know the
statistics of destination
Global Menu --> Control Panel -->System -->Server Administration --> Script
Find script from below GitHub repository.
OR
import
com.liferay.portal.kernel.messaging.Destination; import
com.liferay.portal.kernel.messaging.DestinationConfiguration; import
com.liferay.portal.kernel.messaging.DestinationFactoryUtil; import
com.liferay.portal.kernel.messaging.DummyMessageListener; import
com.liferay.portal.kernel.messaging.Message; import
com.liferay.portal.kernel.messaging.MessageBusUtil; import
com.liferay.portal.kernel.messaging.MessageListener; import
com.liferay.portal.kernel.portlet.PortletClassLoaderUtil; import
com.liferay.portal.kernel.scheduler.SchedulerEngineHelperUtil; import
com.liferay.portal.kernel.scheduler.StorageType; import com.liferay.portal.kernel.scheduler.Trigger; import
com.liferay.portal.kernel.scheduler.TriggerFactoryUtil; import
com.liferay.portal.kernel.util.PortalClassLoaderUtil; import
com.liferay.portal.kernel.messaging.DestinationStatistics; //Create
destination and register listener try { String destinationName =
"liferaysavvy/parallel-destination"; String className =
DummyMessageListener.class.getName(); String jobName = "com.liferay.portal.kernel.messaging.DummyMessageListener"; String groupName =
"com.liferay.portal.kernel.messaging.DummyMessageListener"; //Every minute Destination destiNation =
MessageBusUtil.getDestination(destinationName); if(){ out.println(destiNation.getMessageListeners()); DestinationStatistics
destinationStatistics = destiNation.getDestinationStatistics(); out.println("Destination
is registered with Messagebus::${destiNation.isRegistered()}"); out.println("Sent
Message Count ::
${destinationStatistics.getSentMessageCount()}"); out.println("Pending
Message Count :: ${destinationStatistics.getPendingMessageCount()}"); out.println("Active
Thread Count ::
${destinationStatistics.getActiveThreadCount()}"); out.println("Current
Thread Count ::
${destinationStatistics.getCurrentThreadCount()}"); out.println("Largest
Thread Count ::
${destinationStatistics.getLargestThreadCount()}"); out.println("Max
Thread Pool Size ::
${destinationStatistics.getMaxThreadPoolSize()}"); out.println("Min
Thread Pool Size ::
${destinationStatistics.getMinThreadPoolSize()}"); } else { out.println("************Destination
not in the Message Bus************")); } } catch
(Exception e) { e.printStackTrace(); } |
Important Points
Demonstration purpose, used Dummy Listener and groovy
script to create schedule job. These messages bus destinations will be lost
once restarted the server.
Realtime scenarios we have to create Destinations for every restart. We can use bundle activate method to create destinations and register listeners with listener component class.
Reference Code Points from Liferay
Do not get me incorrect, there are millions of individuals with criminal orange county mugshots records that are relied on with crucial tasks daily. Heck, everybody makes errors or makes bad choices in life.
ReplyDeleteYouTube Channel Review (2021) - YouTube
ReplyDeleteDiscover YouTube Channel Review (2021) online converter of youtube to mp3 and learn about YouTube channels in 2021. Find out what works great on YouTube, the most reliable source for YouTube
https://saglamproxy.com
ReplyDeletemetin2 proxy
proxy satın al
knight online proxy
mobil proxy satın al
CUHEX7
Welcome to ChatGPT Italiano , where language comes alive in the beauty of Italian expression! Immerse yourself in the captivating world of Italian conversation with ChatGPT, your linguistic companion. Whether you're learning the language, refining your skills, or simply savoring the richness of Italian communication, our platform is designed for you. Engage in dynamic dialogues, explore cultural nuances, and elevate your Italian language experience. From everyday conversations to in-depth discussions, ChatGPT Italiano is your key to linguistic enrichment. Embark on a journey where every interaction is an exploration. Start your conversational adventure with ChatGPT Italian Edition today!
ReplyDelete