I am scheduling a job using the code below.
@Controller
@RequestMapping("VIEW")
public class MyController {
@RenderMapping
public String defaultView() {
try {
String cronText = "0 30 12 1/1 * ? *";
String description = "Message Scheduler Description";
String destinationName = DestinationNames.SCHEDULER_DISPATCH;
int exceptionsMaxSize = 0;
String portletId = "portletId";
Message message = new Message();
message.put(SchedulerEngine.MESSAGE_LISTENER_CLASS_NAME,SchedulerListener.class.getName());
message.put(SchedulerEngine.PORTLET_ID, portletId);
Trigger trigger = new CronTrigger(SchedulerListener.class.getName(), SchedulerListener.class.getName(), cronText);
SchedulerEngineHelperUtil.schedule(trigger,StorageType.PERSISTED, description, destinationName, message, exceptionsMaxSize);
}catch (SchedulerException e) {
e.printStackTrace();
}
return "view";
}
}
The problem with the above code is that the scheduler is valid only till the server session. Once this method is executed, I want to trigger the schedulerjob at the mentioned time even after a server restart. Is there a way to implement this in liferay?
This seems to be an issue with the implementation of Liferay scheduling. Quartz is correctly storing and restoring your trigger and the job. But Liferay isn't using your MessageListener
as a job. Instead it will wrap your MessageListener
in a MessageSenderJob
and it will register your MessageListener
.
The MessageSenderJob
will still be triggered after restart, and it will send your message to the message bus. But if you didn't registered your MessageListener
until that point, their will be no receiver of that message.
Solution: You will have to register your MessageListener
on every startup. Either by calling scheduling SchedulerEngineHelperUtil.schedule
again, or by calling MessageBusUtil.registerMessageListener
. See my question here for some options to register startup actions.
Here an example in case you want to create the trigger dynamically (due to some action in the UI):
@WebListener
public class SchedulerListener implements ServletContextListener, PortalLifecycle, MessageListener {
private SchedulerEventMessageListenerWrapper listenerWrapper;
public void contextInitialized(final ServletContextEvent sce) {
// Wait until the portal is ready
PortalLifecycleUtil.register(this, PortalLifecycle.METHOD_INIT);
}
public void portalInit() {
// Register our listener
listenerWrapper = new SchedulerEventMessageListenerWrapper();
listenerWrapper.setGroupName(getClass().getName());
listenerWrapper.setJobName(getClass().getName());
listenerWrapper.setMessageListener(this);
listenerWrapper.afterPropertiesSet();
MessageBusUtil.registerMessageListener(DestinationNames.SCHEDULER_DISPATCH, listenerWrapper);
}
public void contextDestroyed(final ServletContextEvent event) {
// Unregister
if (listenerWrapper != null) {
MessageBusUtil.unregisterMessageListener(DestinationNames.SCHEDULER_DISPATCH, listenerWrapper);
}
}
public void portalDestroy() {
// Ignore
}
public void receive(final Message message) {
// ... your job code here ...
}
}
If you want to have a fixed trigger instead, you can drop the listenerWrapper
and put your SchedulerEngineHelperUtil.schedule(...)
code from your question into portalInit()
.
If you want to know, what's the point of StorageType.PERSISTED
: It's for executing triggers that would have been fired while the server was down or that had just started as the server was going down.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With