Spring scheduled jobs are a convenient way to run scheduled jobs in Java applications, but they have limitations in enterprise scenarios. By integrating with SchedulerX, you can add enterprise-grade capabilities to your jobs.
Prerequisites
-
Agent version 1.8.13 or later.
-
A Spring Boot application is connected to the SchedulerX platform. For more information, see Connect a Spring Boot application to SchedulerX.
Integration
Step 1: Add pom dependency
For a Spring Boot application, add the following dependency to the pom.xml file.
Set schedulerx2.version to the latest agent version. For more information, see Agent release notes.
<dependency>
<groupId>com.aliyun.schedulerx</groupId>
<artifactId>schedulerx2-spring-boot-starter</artifactId>
<version>${schedulerx2.version}</version>
<!-- If you use Logback, you must exclude the Log4j and Log4j2 dependencies -->
<exclusions>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
</exclusion>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
Whether you are creating a new Spring scheduled job or using an existing one, you must keep the @EnableScheduling annotation on your main class.
@SpringBootApplication
@EnableScheduling /** Enable Spring scheduled jobs */
public class SchedulerXWorkerApplication {
public static void main(String[] args) {
SpringApplication.run(SchedulerXWorkerApplication.class, args);
}
}
/** A native Spring scheduled job class */
@Service
public class SpringScheduledProcessor {
@Scheduled(cron = "0/2 * * * * ?")
public void hello() {
logger.info(DateUtil.now() + " hello world. start");
logger.info(DateUtil.now() + " hello world. end");
}
}
For new or existing applications with this configuration, SchedulerX does not take over the Spring scheduled jobs by default. The jobs continue to be scheduled by the Spring container. This ensures that your existing Spring scheduled jobs are not affected.
Step 2: Add configuration parameters
To allow SchedulerX to manage your Spring scheduled jobs, add the following configuration to your Properties file.
# 1. Application access configuration
spring.schedulerx2.endpoint=${endpoint}
spring.schedulerx2.namespace=${namespace}
spring.schedulerx2.groupId=${groupId}
spring.schedulerx2.appKey=${appKey}
# 2. Enable SchedulerX to take over Spring scheduled jobs
spring.schedulerx2.task.scheduling.scheduler=schedulerx
# 3. (Optional) Enable automatic synchronization for jobs
#spring.schedulerx2.task.scheduling.sync=true
#spring.schedulerx2.regionId=The target region ID for synchronization. For more information about region IDs, see Endpoints.
#spring.schedulerx2.aliyunAccessKey=XXXXXXXXX
#spring.schedulerx2.aliyunSecretKey=XXXXXXXXX
Parameter description:
-
Application access configuration: Log on to the MSE SchedulerX console. In the left-side navigation pane, click Application Management. On the Applications page, find your application and click Access Config in the Actions column to get the configuration details. If this is your first time connecting an application, you must create an application group.
-
Enable automatic job synchronization: If you have a large number of existing Spring scheduled jobs, you can enable automatic synchronization in the application's configuration file. This greatly simplifies the manual creation process described in Step 3. For the region ID in the configuration, see the region ID in Endpoints.
To maintain consistency with how native Spring jobs run in a cluster, automatically synchronized jobs default to the Broadcast run execution mode. This means that the job runs on every machine in the cluster at the scheduled time. If you need the job to run on only one machine selected from the cluster, you can edit the job in the console and change the execution mode to Stand-alone operation. For more information about the parameters, see Step 3.
Step 3: Create a scheduled job manually (optional)
If you enabled automatic synchronization in Step 2, you do not need to perform this step.
Log on to the MSE SchedulerX console.
-
In the left-side navigation pane, click Task Management.
-
On the Task Management page, click Add Task. Select the SpringSchedule task type, and configure the class name and method name for the scheduled job.
Parameter
Description
Task name
The name of the job.
Description
A brief description of the job to simplify searching and management.
Application ID
The application group to which the job belongs. Select a value from the drop-down list.
Task Type
The language in which the job is implemented. Supported types include Java, Shell, Python, Go, HTTP, Node.js, XXL-JOB, and DataWorks. For Shell, Python, and Go, an editor appears where you can write the job script.
In this topic, the task type is SpringSchedule.
Spring Schedule configuration
The fully qualified class name and the method name of the scheduled job.
Execution Mode
The mode in which the job is executed. The following modes are supported:
-
Stand-alone operation: Runs on one randomly selected machine.
-
Broadcast run: Runs on all machines at the same time and waits for all of them to finish.
NoteThe parameters in the advanced settings vary depending on the selected execution mode.
Priority
When multiple jobs in the same application run on the same instance, jobs with a higher priority are executed first. However, if jobs are distributed across multiple instances, a lower-priority job might be executed first if it is scheduled to a different instance. SchedulerX prevents this using a preemptible priority queue, which ensures that high-priority jobs in the queue are always executed first. For more information, see Use job priority queues for application-level rate limiting.
Task Parameters
You can retrieve these parameters from the job context at runtime.
-
-
Configure the trigger frequency.
NoteThe frequency configured in the console takes precedence. The configuration in the native
@Scheduledannotation in your Spring scheduled job code is ignored, but you must keep the annotation in the code.The time parameters are described as follows:
Parameter
Description
Time type
-
none: No scheduling type. Usually triggered by a workflow.
-
cron: A cron expression.
-
api: Triggered by an API call.
-
fixed_rate: A fixed frequency.
-
second_delay: A fixed delay in seconds.
-
one_time: A one-time job.
cron expression (for cron type only)
Enter a cron expression. You can either enter it directly or use a tool to generate and validate it.
Fixed frequency (for fixed_rate type only)
The minimum supported frequency is 60 seconds. For example, a value of 200 schedules the job to run every 200 seconds.
Fixed delay (for second_delay type only)
Valid values are 1 to 60. For example, a value of 5 triggers the job after a 5-second delay.
The advanced configuration parameters are described as follows:
Parameter
Description
Data Timestamp Offset
This value can be retrieved from the job context during scheduling.
Time zone
You can select a time zone based on your needs, including common countries or regions, as well as standard GMT formats.
Calendar
Select Workday or Financial day.
-
-
Set alert conditions and notification channels. For more information about notification channels, see Notification contacts.
After you complete these steps, the SchedulerX platform takes over and runs your Spring scheduled jobs. You can use enterprise-grade features such as visual management, job log queries, execution tracing, and alert notifications.
Step 4: Verify job integration
-
Start your Spring application. After the application starts, log on to the MSE SchedulerX console. In the left-side navigation pane, click Application Management and check for connected instances in the application group. The presence of instances confirms a successful connection.
In the application list, confirm that the Total number of instances for the target application is greater than 0. Click View instances in the Operation column to view instance details.
-
In the left-side navigation pane, click Task Management. Find the job that corresponds to your application, and in the Actions column, click Run once. A successful run indicates that the setup is complete.
FAQ
Why does the original Spring timer still run after SchedulerX takes over?
If a custom scheduler is specified in your application, SchedulerX overwrites the custom scheduler. This conflict typically occurs when a class implements org.springframework.scheduling.annotation.SchedulingConfigurer and calls the setScheduler method of ScheduledTaskRegistrar, which overwrites the default scheduler.
To resolve this issue:
Search your project for any class that implements
SchedulingConfigurer.Check whether the
setSchedulermethod ofScheduledTaskRegistraris called.If either condition is true, comment out the custom scheduler code.
How do I get the job context in a Spring job?
Call ContainerFactory.getContainerPool().getContext() to get the current JobContext:
// Get the SchedulerX job context inside a @Scheduled method
JobContext jobContext = ContainerFactory.getContainerPool().getContext();Can a Spring job return a processing result?
This feature requires SchedulerX agent version later than 1.10.11. Versions 1.10.11 and earlier do not support return values from Spring jobs.
The processing results are returned based on the specified scheduling methods. Spring jobs support two return types:
| Return type | Use case |
|---|---|
ProcessResult | Return a success/failure status with a result message |
String | Return a result message only |
Both examples below use the @Scheduled annotation with a cron expression.
Return a ProcessResult
Use ProcessResult to indicate success or failure along with a result message:
@Scheduled(cron = "0/5 * * * * ?")
public ProcessResult helloStandalone1() {
try {
logger.info(DateUtil.now() + " " + Thread.currentThread().getName() + " hello world. start");
TimeUnit.SECONDS.sleep(2L);
logger.info(DateUtil.now() + " " + Thread.currentThread().getName() + " hello world. end");
} catch (Exception e) {
e.printStackTrace();
logger.info(DateUtil.now() + " " + Thread.currentThread().getName() + " hello world. exception end..");
}
// First argument: true for success, false for failure
// Second argument: result message
return new ProcessResult(true, "Processing result");
}Return a String
Return a String directly when you do not need an explicit success/failure flag:
@Scheduled(cron = "0/5 * * * * ?")
public String helloStandalone2() {
try {
logger.info(DateUtil.now() + " " + Thread.currentThread().getName() + " hello world. start");
TimeUnit.SECONDS.sleep(2L);
logger.info(DateUtil.now() + " " + Thread.currentThread().getName() + " hello world. end");
} catch (Exception e) {
e.printStackTrace();
logger.info(DateUtil.now() + " " + Thread.currentThread().getName() + " hello world. exception end..");
}
return "Processing result";
}