Manually Programming Scheduled Jobs
Implementing the SchedulerJobConfiguration interface provides greater flexibility and improved performance as it is closer to the core of the job scheduler framework. However, the Job Scheduler UI offers more customization options and data on traditional Job Scheduler tasks than on scheduled jobs created using SchedulerJobConfiguration.
Before Liferay DXP 2023.Q4/Portal GA93, the alternative to DispatchTaskExecutor was MessageListener.
The Job Scheduler application’s Scheduled Jobs tab lists all scheduled jobs created this way. Here you can view general details for each job (e.g., name, status), as well as manually initiate runs or pause/resume jobs individually.

Deploy the Sample Code
Start a new Liferay instance by running
docker run -it -m 8g -p 8080:8080 liferay/portal:7.4.3.132-ga132
Sign in to Liferay at http://localhost:8080. Use the email address test@liferay.com and the password test. When prompted, change the password to learn.
Then, follow these steps:
- 
Download and unzip the example project: curl https://resources.learn.liferay.com/examples/liferay-p1p9.zip -Ounzip liferay-p1p9.zip
- 
Build and deploy the project module. cd liferay-p1p9./gradlew deploy -Ddeploy.docker.container.id=$(docker ps -lq)NoteThis command is the same as copying the compiled module JAR to /opt/liferay/osgi/moduleson the Docker container.
- 
Confirm the deployment in the Liferay Docker container console. STARTED com.acme.p1p9.impl_1.0.0 [2177]
- 
Verify the scheduled job logs messages to the console every 30 seconds: INFO [http-nio-8080-exec-6][P1P9SchedulerJobConfiguration:20] Invoking #getJobExecutorUnsafeRunnable
Implementing SchedulerJobConfiguration
The SchedulerJobConfiguration interface defines two methods to be overridden:
- getJobExecutorUnsafeRunnabledefines what the scheduled job does.
- getTriggerConfigurationdefines when the scheduled job runs.
To create scheduled jobs using this interface,
- Add a @Componentannotation above your class declaration to register your implementation as a scheduled job component:
@Component(service = SchedulerJobConfiguration.class)
public class P1P9SchedulerJobConfiguration
	implements SchedulerJobConfiguration {
- Override the getJobExecutorUnsafeRunnablemethod. This method returns a function with all the logic you want to execute whenever the scheduled job is run:
@Override
public UnsafeRunnable<Exception> getJobExecutorUnsafeRunnable() {
	return () -> {
		if (_log.isInfoEnabled()) {
			_log.info("Invoking #getJobExecutorUnsafeRunnable");
		}
	};
}
- Override the getTriggerConfigurationmethod. This method defines the conditions in which the scheduled job should run. In the example module, it runs on a 30 second timer:
@Override
public TriggerConfiguration getTriggerConfiguration() {
	return TriggerConfiguration.createTriggerConfiguration(
		30, TimeUnit.SECOND);
}
You can create TriggerConfigurations using regular cron expressions or with Liferay’s TimeUnit.