Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Liferay Scheduler not working after server restart

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?

like image 245
Philip John Avatar asked Oct 31 '22 14:10

Philip John


1 Answers

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.

like image 193
Tobias Liefke Avatar answered Nov 15 '22 03:11

Tobias Liefke