Liferay is a Gartner Magic Quadrant Leader for the Sixth Year! Find out why

Forums

Home » Liferay Portal » English » 3. Development

Combination View Flat View Tree View
Threads [ Previous | Next ]
toggle
Charalampos Chrysikopoulos
Liferay 6 - Programmatically scheduling a job
December 15, 2011 6:14 AM
Answer

Charalampos Chrysikopoulos

Rank: Junior Member

Posts: 27

Join Date: December 8, 2011

Recent Posts

Hello everyone,

in my portlet I have the need of a UI, where the user can schedule some jobs.

That's why the scheduling through the configuration of liferay-portlet.xml is not a solution.

I'd like to be able to create some triggers of my own and schedule them for a given Job.
I created a class that implements MessageListener:
1
2public class MyJob implements MessageListener {
3
4    @Override
5    public void receive(Message message) {
6              // do my stuff here
7        }
8}


Then I tried to use SchedulerEngineUtil to schedule this job:
1
2SchedulerEntry entry = new SchedulerEntryImpl();
3entry.setEventListenerClass(someClassName);
4entry.setTriggerValue(someCronString);
5entry.setTriggerType(TriggerType.CRON);
6entry.setDescription(someClassName);
7       
8SchedulerEngineUtil.schedule(entry, this.getClass().getClassLoader());


The above code doesn't create any errors. After running the code in the portlet and looking at the QUARTZ tables in the database, everything seems correct. The job is there and the trigger too.

But its never fired. No errors. No feedback from the portal scheduler. Simply my job is never fired.

With exactly the same job class, when I try to run my job through liferay-portlet.xml like:
 1
 2        <scheduler-entry>
 3            <scheduler-description>My description</scheduler-description>
 4            <scheduler-event-listener-class>somePackage.MyJob</scheduler-event-listener-class>
 5            <trigger>
 6                <cron>
 7                    <cron-trigger-value>someTriggerString</cron-trigger-value>
 8                </cron>
 9            </trigger>
10        </scheduler-entry>

I see exactly the same entries in the QUARTZ tables in the database, and the job fires as the trigger commands.

Does someone has any suggestions, what to do?
Charalampos Chrysikopoulos
RE: Liferay 6 - Programmatically scheduling a job
December 16, 2011 5:31 AM
Answer

Charalampos Chrysikopoulos

Rank: Junior Member

Posts: 27

Join Date: December 8, 2011

Recent Posts

As a workaround I used my own quartz scheduler in the portlet with different tables in the database and this works fine, but its a workaround and not a clean work. If someone knows how to schedule a job programmatically, please help me. Thanks a lot.
Jitendra Rajput
RE: Liferay 6 - Programmatically scheduling a job
December 23, 2011 11:36 AM
Answer

Jitendra Rajput

Rank: Liferay Master

Posts: 858

Join Date: January 7, 2011

Recent Posts

If u want to run scheduler based on user inputs at run time i would suggest implement your own quartz scheduler .
And get the cron expression from preferences . and when ever user update scheduler time update preferences so scheduler timings will be automatically changed
Charalampos Chrysikopoulos
RE: Liferay 6 - Programmatically scheduling a job
December 27, 2011 11:47 PM
Answer

Charalampos Chrysikopoulos

Rank: Junior Member

Posts: 27

Join Date: December 8, 2011

Recent Posts

Thank you for your answer Jitendra. What you describe is what I finally did in my second post because I was in a dead-end and under time pressure. But I would like to know the "right" way to do using the liferay API, if something like this is even possible in the current version.
Jelmer Kuperus
RE: Liferay 6 - Programmatically scheduling a job
December 27, 2011 6:35 AM
Answer

Jelmer Kuperus

Rank: Liferay Legend

Posts: 1192

Join Date: March 10, 2010

Recent Posts

I am not sure why its not working for you but i've done it from a startup action in liferay 6.0.6 and that worked fine

1Thread thread = Thread.currentThread();
2SchedulerEngineUtil.schedule(DocumentConversionJob.SCHEDULER_ENTRY, thread.getContextClassLoader());


 1public class DocumentConversionJob implements MessageListener {
 2
 3    public static final SchedulerEntry SCHEDULER_ENTRY = new SchedulerEntryImpl() {
 4        {
 5            setDescription("Job that processes pending document conversion requests asynchronously");
 6            setTriggerType(TriggerType.SIMPLE);
 7            setTimeUnit(TimeUnit.SECOND);
 8            setTriggerValue("30");
 9            setEventListenerClass(DocumentConversionJob.class.getName());
10        }
11    };
12
13....
Charalampos Chrysikopoulos
RE: Liferay 6 - Programmatically scheduling a job
December 28, 2011 12:17 AM
Answer

Charalampos Chrysikopoulos

Rank: Junior Member

Posts: 27

Join Date: December 8, 2011

Recent Posts

I tried your approach and it worked fine. Thanks for that.
Andreea Ardelean
RE: Liferay 6 - Programmatically scheduling a job
January 16, 2012 10:51 AM
Answer

Andreea Ardelean

Rank: New Member

Posts: 1

Join Date: July 21, 2011

Recent Posts

Hi there,

I have a portlet that I use to schedule programmatically a job that has a cron trigger. Job is in quartz tables and fired when it is set.

If I restart application server, job is not in quarz tables anymore.
Is there a way (some property to be set) that can help me block this deletion at re-start of the server?

Thanks in advance
Charalampos Chrysikopoulos
RE: Liferay 6 - Programmatically scheduling a job
February 10, 2012 5:26 AM
Answer

Charalampos Chrysikopoulos

Rank: Junior Member

Posts: 27

Join Date: December 8, 2011

Recent Posts

Could you describe how did you configured your jobs?
Nagendra Kumar Busam
RE: Liferay 6 - Programmatically scheduling a job
April 5, 2013 8:11 PM
Answer

Nagendra Kumar Busam

Rank: Liferay Master

Posts: 653

Join Date: July 7, 2009

Recent Posts

Hi,
I was doing something similar to what you have mentioned. In my local jobs are executing fine. Where as on our Dev & QA servers when processing is taking more time, there are multiple threads running for same job when I run once. How can overcome multiple threads from running.

Thanks in advance
Riccardo Noviello
RE: Liferay 6 - Programmatically scheduling a job
December 14, 2013 3:03 PM
Answer

Riccardo Noviello

Rank: New Member

Posts: 6

Join Date: November 29, 2013

Recent Posts

In Liferay 6.1 there is no method schedule(SchedulerEntry arg0, ContextClassLoader arg1) anymore.

Also there seems to be an issue with the registration of the MessageListener. I have managed to make work this code at run time:


//Create the Message
Message message = new Message();
message.put("message", "Hello this is a reminder");
message.put("email", "6@gmail.com");

//My custom Job Listener class (Implements MessageListener)
ScheduledJobListener job = new ScheduledJob();

//Create the trigger for the job
Trigger trigger = new CronTrigger("The Job Name", "The Group Name", new Date(),null, " 0/10 1/1 * 1/1 * ? *"); //triggers every 10 seconds

cronJob.setTrigger(trigger);

System.out.println("Scheduling "+trigger.getJobName());

//Schedule new Job
MessageBusUtil.registerMessageListener(DestinationNames.SCHEDULER_DISPATCH, job);
SchedulerEngineUtil.schedule(trigger, StorageType.PERSISTED,trigger.getJobName(), DestinationNames.SCHEDULER_DISPATCH, message, 10);


Which works, however when you restart your server, the scheduler does not start working the jobs persisted in your DB, until you schedule a new instance of the same listener (ScheduledJobListener)...So I am starting thinking there might be an issue with the registration/un-registration of the Listeners.
Perhaps I am following the wrong approach, so please suggest.

P.S. If I don't register the MessageBusUtil.registerMessageListener the job never triggers...
Ahmed Kamel
RE: Liferay 6 - Programmatically scheduling a job
December 25, 2013 5:28 AM
Answer

Ahmed Kamel

Rank: New Member

Posts: 13

Join Date: April 28, 2011

Recent Posts

I'm facing the same problem, Did you find the solution?
Duy Nguyen
RE: Liferay 6 - Programmatically scheduling a job
January 3, 2014 2:09 AM
Answer

Duy Nguyen

Rank: New Member

Posts: 3

Join Date: June 14, 2013

Recent Posts

Riccardo Noviello:
In Liferay 6.1 there is no method schedule(SchedulerEntry arg0, ContextClassLoader arg1) anymore.

Also there seems to be an issue with the registration of the MessageListener. I have managed to make work this code at run time:


//Create the Message
Message message = new Message();
message.put("message", "Hello this is a reminder");
message.put("email", "6@gmail.com");

//My custom Job Listener class (Implements MessageListener)
ScheduledJobListener job = new ScheduledJob();

//Create the trigger for the job
Trigger trigger = new CronTrigger("The Job Name", "The Group Name", new Date(),null, " 0/10 1/1 * 1/1 * ? *"); //triggers every 10 seconds

cronJob.setTrigger(trigger);

System.out.println("Scheduling "+trigger.getJobName());

//Schedule new Job
MessageBusUtil.registerMessageListener(DestinationNames.SCHEDULER_DISPATCH, job);
SchedulerEngineUtil.schedule(trigger, StorageType.PERSISTED,trigger.getJobName(), DestinationNames.SCHEDULER_DISPATCH, message, 10);


Which works, however when you restart your server, the scheduler does not start working the jobs persisted in your DB, until you schedule a new instance of the same listener (ScheduledJobListener)...So I am starting thinking there might be an issue with the registration/un-registration of the Listeners.
Perhaps I am following the wrong approach, so please suggest.

P.S. If I don't register the MessageBusUtil.registerMessageListener the job never triggers...


Hi Ricardo,

Actually I can run the job without need to register MessageBusUtil.registerMessageListener, we also do not need to:
cronJob.setTrigger(trigger);

But also get the same problem as yours, somehow when restarting server job not resumed correctly, I need to delete jobs in db, then reset job information via GUI, then it runs.

Its a big problem with us because we need to set a lot of jobs scheduled at different time.

Appreciate a lot any help in resuming jobs when server restart.

Thanks
Duy Nguyen
RE: Liferay 6 - Programmatically scheduling a job
March 13, 2014 2:53 AM
Answer

Duy Nguyen

Rank: New Member

Posts: 3

Join Date: June 14, 2013

Recent Posts

Hi all,

Finally I found out the solution to schedule a job programmatically and restart it successfully, I wanna share my experience here for you guys.
1. Create custom Destination name instead of using DestinationNames.SCHEDULER_DISPATCH:
We use init() method to add custom Destination to MessageBusUtil (required):
1   _log.info("Restart existing job scheduler...");
2            if(MessageBusUtil.getMessageBus().getDestination("Sample Dest") == null) {
3                Destination dest = new ParallelDestination("Sample Dest");
4                MessageBusUtil.addDestination(dest);
5            }


2. Get all information from GUI, info such as start time, end time, cron expression, then you schedule NEW job via ScheduleEngineUtil:
1SchedulerEngineUtil.schedule(trigger, StorageType.PERSISTED,
2                        description, destination, message, 0);


3. In case you want to update existing job, use update instead:
1SchedulerEngineUtil.update(trigger, StorageType.PERSISTED);


4. To handle when server restart, first we need to recalculate next start time, then call:
1SchedulerEngineUtil.schedule(trigger, StorageType.PERSISTED,
2                        description, destination, message, 0);

5. How to build trigger:
1 CronTrigger trigger = new CronTrigger(jobName, groupName,
2                startTimeTrigger, cronExpression);

We did test and it worked really well, I found out liferay scheduler is tough task and this is the way how we solved the problem, hope it help.

Regards,
Duy
Charalampos Chrysikopoulos
RE: Liferay 6 - Programmatically scheduling a job
March 11, 2014 1:04 AM
Answer

Charalampos Chrysikopoulos

Rank: Junior Member

Posts: 27

Join Date: December 8, 2011

Recent Posts

Very interesting. I will try this out when I have time and post my results.
Sai Sriharsha Kasturi
RE: Liferay 6 - Programmatically scheduling a job
May 8, 2015 6:36 AM
Answer

Sai Sriharsha Kasturi

Rank: New Member

Posts: 19

Join Date: October 21, 2012

Recent Posts

I achieved it through the following way,

1. Extend your scheduler class to MVCPortlet and implement to MessageListener interface.
2. Now, override init() method by placing the following code,

 1String cron = "0 0/1 * 1/1 * ? *"; // You can read it from portal-ext.properties using PropsUtil
 2         Trigger trigger = null; 
 3          try { 
 4           trigger = TriggerFactoryUtil.buildTrigger(TriggerType.CRON, {you implemented scheduler class name}, {you implemented scheduler class name}, new Date(), null, cron); 
 5          } catch (SchedulerException e) { 
 6           e.printStackTrace(); 
 7          } 
 8            
 9          Message message = new Message(); 
10          //message.put(SchedulerEngine.CONTEXT_PATH, portlet.getContextPath()); 
11          message.put(SchedulerEngine.MESSAGE_LISTENER_CLASS_NAME, {you implemented scheduler class name}); 
12          message.put(SchedulerEngine.PORTLET_ID, portlet.getPortletId()); 
13            
14          try { 
15           SchedulerEngineHelperUtil.schedule(trigger, StorageType.PERSISTED, "", "liferay/scheduler_dispatch", message, 5); 
16          } catch (SchedulerException e) { 
17           e.printStackTrace(); 
18          }


3. Now, you can place your logic in the receive() method,

1@Override
2    public void receive(Message message) throws MessageListenerException {
3        LOGGER.info("IN: Dynamic scheduler");
4}


4. Finally, give the complete path of your implemented class in liferay-portlet.xml, as below

1 <portlet-class>com.test.MyScheduler</portlet-class>



Hope this helps,
Harsha