留言板

Liferay 6 - Programmatically scheduling a job

thumbnail
Charalampos Chrysikopoulos,修改在12 年前。

Liferay 6 - Programmatically scheduling a job

Junior Member 帖子: 79 加入日期: 11-12-9 最近的帖子
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,修改在12 年前。

RE: Liferay 6 - Programmatically scheduling a job

Junior Member 帖子: 79 加入日期: 11-12-9 最近的帖子
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,修改在12 年前。

RE: Liferay 6 - Programmatically scheduling a job

Liferay Master 帖子: 875 加入日期: 11-1-7 最近的帖子
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,修改在12 年前。

RE: Liferay 6 - Programmatically scheduling a job

Junior Member 帖子: 79 加入日期: 11-12-9 最近的帖子
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,修改在12 年前。

RE: Liferay 6 - Programmatically scheduling a job (答复)

Liferay Legend 帖子: 1191 加入日期: 10-3-10 最近的帖子
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,修改在12 年前。

RE: Liferay 6 - Programmatically scheduling a job

Junior Member 帖子: 79 加入日期: 11-12-9 最近的帖子
I tried your approach and it worked fine. Thanks for that.
Andreea Ardelean,修改在12 年前。

RE: Liferay 6 - Programmatically scheduling a job

New Member 发布: 1 加入日期: 11-7-21 最近的帖子
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,修改在12 年前。

RE: Liferay 6 - Programmatically scheduling a job

Junior Member 帖子: 79 加入日期: 11-12-9 最近的帖子
Could you describe how did you configured your jobs?
thumbnail
Nagendra Kumar Busam,修改在11 年前。

RE: Liferay 6 - Programmatically scheduling a job

Liferay Master 帖子: 678 加入日期: 09-7-7 最近的帖子
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,修改在10 年前。

RE: Liferay 6 - Programmatically scheduling a job

New Member 帖子: 6 加入日期: 13-11-29 最近的帖子
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,修改在10 年前。

RE: Liferay 6 - Programmatically scheduling a job

New Member 帖子: 13 加入日期: 11-4-28 最近的帖子
I'm facing the same problem, Did you find the solution?
Duy Nguyen,修改在10 年前。

RE: Liferay 6 - Programmatically scheduling a job

New Member 帖子: 3 加入日期: 13-6-14 最近的帖子
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,修改在10 年前。

RE: Liferay 6 - Programmatically scheduling a job

New Member 帖子: 3 加入日期: 13-6-14 最近的帖子
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,修改在10 年前。

RE: Liferay 6 - Programmatically scheduling a job

Junior Member 帖子: 79 加入日期: 11-12-9 最近的帖子
Very interesting. I will try this out when I have time and post my results.
thumbnail
Sai Sriharsha Kasturi,修改在8 年前。

RE: Liferay 6 - Programmatically scheduling a job

Junior Member 帖子: 34 加入日期: 12-10-21 最近的帖子
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