Foren

Liferay 6 - Programmatically scheduling a job

thumbnail
Charalampos Chrysikopoulos, geändert vor 12 Jahren.

Liferay 6 - Programmatically scheduling a job

Junior Member Beiträge: 79 Beitrittsdatum: 09.12.11 Neueste Beiträge
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:

public class MyJob implements MessageListener {

	@Override
	public void receive(Message message) {
              // do my stuff here
        }
}


Then I tried to use SchedulerEngineUtil to schedule this job:

SchedulerEntry entry = new SchedulerEntryImpl();
entry.setEventListenerClass(someClassName);
entry.setTriggerValue(someCronString);
entry.setTriggerType(TriggerType.CRON);
entry.setDescription(someClassName);
		
SchedulerEngineUtil.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:

		<scheduler-entry> 
			<scheduler-description>My description</scheduler-description>
			<scheduler-event-listener-class>somePackage.MyJob</scheduler-event-listener-class>
			<trigger>
				<cron>
					<cron-trigger-value>someTriggerString</cron-trigger-value>
				</cron>
			</trigger>
		</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?
thumbnail
Charalampos Chrysikopoulos, geändert vor 12 Jahren.

RE: Liferay 6 - Programmatically scheduling a job

Junior Member Beiträge: 79 Beitrittsdatum: 09.12.11 Neueste Beiträge
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.
thumbnail
Jitendra Rajput, geändert vor 12 Jahren.

RE: Liferay 6 - Programmatically scheduling a job

Liferay Master Beiträge: 875 Beitrittsdatum: 07.01.11 Neueste Beiträge
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
thumbnail
Charalampos Chrysikopoulos, geändert vor 12 Jahren.

RE: Liferay 6 - Programmatically scheduling a job

Junior Member Beiträge: 79 Beitrittsdatum: 09.12.11 Neueste Beiträge
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.
thumbnail
jelmer kuperus, geändert vor 12 Jahren.

RE: Liferay 6 - Programmatically scheduling a job (Antwort)

Liferay Legend Beiträge: 1191 Beitrittsdatum: 10.03.10 Neueste Beiträge
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

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


public class DocumentConversionJob implements MessageListener {

    public static final SchedulerEntry SCHEDULER_ENTRY = new SchedulerEntryImpl() {
        {
            setDescription("Job that processes pending document conversion requests asynchronously");
            setTriggerType(TriggerType.SIMPLE);
            setTimeUnit(TimeUnit.SECOND);
            setTriggerValue("30");
            setEventListenerClass(DocumentConversionJob.class.getName());
        }
    };

....
thumbnail
Charalampos Chrysikopoulos, geändert vor 12 Jahren.

RE: Liferay 6 - Programmatically scheduling a job

Junior Member Beiträge: 79 Beitrittsdatum: 09.12.11 Neueste Beiträge
I tried your approach and it worked fine. Thanks for that.
Andreea Ardelean, geändert vor 12 Jahren.

RE: Liferay 6 - Programmatically scheduling a job

New Member Beitrag: 1 Beitrittsdatum: 21.07.11 Neueste Beiträge
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
thumbnail
Charalampos Chrysikopoulos, geändert vor 12 Jahren.

RE: Liferay 6 - Programmatically scheduling a job

Junior Member Beiträge: 79 Beitrittsdatum: 09.12.11 Neueste Beiträge
Could you describe how did you configured your jobs?
thumbnail
Nagendra Kumar Busam, geändert vor 10 Jahren.

RE: Liferay 6 - Programmatically scheduling a job

Liferay Master Beiträge: 678 Beitrittsdatum: 07.07.09 Neueste Beiträge
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, geändert vor 10 Jahren.

RE: Liferay 6 - Programmatically scheduling a job

New Member Beiträge: 6 Beitrittsdatum: 29.11.13 Neueste Beiträge
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, geändert vor 10 Jahren.

RE: Liferay 6 - Programmatically scheduling a job

New Member Beiträge: 13 Beitrittsdatum: 28.04.11 Neueste Beiträge
I'm facing the same problem, Did you find the solution?
Duy Nguyen, geändert vor 10 Jahren.

RE: Liferay 6 - Programmatically scheduling a job

New Member Beiträge: 3 Beitrittsdatum: 14.06.13 Neueste Beiträge
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, geändert vor 10 Jahren.

RE: Liferay 6 - Programmatically scheduling a job

New Member Beiträge: 3 Beitrittsdatum: 14.06.13 Neueste Beiträge
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):
   _log.info("Restart existing job scheduler...");
			if(MessageBusUtil.getMessageBus().getDestination("Sample Dest") == null) {
				Destination dest = new ParallelDestination("Sample Dest");
				MessageBusUtil.addDestination(dest);
			}


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


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


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

5. How to build trigger:
 CronTrigger trigger = new CronTrigger(jobName, groupName,
				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
thumbnail
Charalampos Chrysikopoulos, geändert vor 10 Jahren.

RE: Liferay 6 - Programmatically scheduling a job

Junior Member Beiträge: 79 Beitrittsdatum: 09.12.11 Neueste Beiträge
Very interesting. I will try this out when I have time and post my results.
thumbnail
Sai Sriharsha Kasturi, geändert vor 8 Jahren.

RE: Liferay 6 - Programmatically scheduling a job

Junior Member Beiträge: 34 Beitrittsdatum: 21.10.12 Neueste Beiträge
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,

String cron = "0 0/1 * 1/1 * ? *"; // You can read it from portal-ext.properties using PropsUtil
		 Trigger trigger = null;  
		  try {  
		   trigger = TriggerFactoryUtil.buildTrigger(TriggerType.CRON, {you implemented scheduler class name}, {you implemented scheduler class name}, new Date(), null, cron);  
		  } catch (SchedulerException e) {  
		   e.printStackTrace();  
		  }  
		    
		  Message message = new Message();  
		  //message.put(SchedulerEngine.CONTEXT_PATH, portlet.getContextPath());  
		  message.put(SchedulerEngine.MESSAGE_LISTENER_CLASS_NAME, {you implemented scheduler class name});  
		  message.put(SchedulerEngine.PORTLET_ID, portlet.getPortletId());  
		    
		  try {  
		   SchedulerEngineHelperUtil.schedule(trigger, StorageType.PERSISTED, "", "liferay/scheduler_dispatch", message, 5);  
		  } catch (SchedulerException e) {  
		   e.printStackTrace();  
		  }


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

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


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

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



Hope this helps,
Harsha