All Products
Search
Document Center

SchedulerX:Spring jobs

Last Updated:Mar 10, 2026

SchedulerX takes over your existing Spring @Scheduled jobs with minimal code changes, adding centralized management, monitoring, alerting, and distributed scheduling -- without modifying your job logic or annotations.

How it works

SchedulerX replaces the default Spring task scheduler with its own scheduling engine:

  1. Add the SchedulerX Spring Boot starter dependency to your project.

  2. Set spring.schedulerx2.task.scheduling.scheduler=schedulerx in your application properties.

  3. SchedulerX takes control of all @Scheduled methods and manages their execution through the console.

After takeover, the SchedulerX console controls scheduling frequency. The cron expressions in your @Scheduled annotations remain in the code but no longer determine when jobs run.

Execution modes:

ModeBehaviorUse case
Broadcast runEvery worker node runs the job simultaneously.Cache refresh, log cleanup, configuration reload -- tasks that every node must perform. Matches native Spring @Scheduled behavior.
Stand-alone operationOne randomly selected worker runs the job.Data aggregation, report generation, email dispatch -- tasks that should run exactly once across the cluster.

Auto-synchronized jobs default to Broadcast run to preserve native Spring behavior. To run a job on only one node, change the Execution mode to Stand-alone operation in the console.

Prerequisites

Add the Maven dependency

Add the schedulerx2-spring-boot-starter dependency to your pom.xml. Replace schedulerx2.version with the latest version from the agent release notes.

<dependency>
  <groupId>com.aliyun.schedulerx</groupId>
  <artifactId>schedulerx2-spring-boot-starter</artifactId>
  <version>${schedulerx2.version}</version>
  <!-- Exclude Log4j if your application uses Logback -->
  <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>

Keep @EnableScheduling in your main class regardless of whether SchedulerX handles scheduling:

@SpringBootApplication
@EnableScheduling // Required -- do not remove
public class SchedulerXWorkerApplication {
    public static void main(String[] args) {
        SpringApplication.run(SchedulerXWorkerApplication.class, args);
    }
}

Existing @Scheduled job classes need no changes:

@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");
    }
}
Adding the dependency alone does not change job behavior. SchedulerX does not take over Spring scheduled jobs by default -- they continue running in the Spring container until you enable takeover in the next step.

Configure SchedulerX takeover

Add these properties to your application.properties file:

# Connect to SchedulerX
spring.schedulerx2.endpoint=${endpoint}
spring.schedulerx2.namespace=${namespace}
spring.schedulerx2.groupId=${groupId}
spring.schedulerx2.appKey=${appKey}

# Enable SchedulerX to take over Spring scheduled jobs
spring.schedulerx2.task.scheduling.scheduler=schedulerx

To get the connection parameters (endpoint, namespace, groupId, appKey):

  1. Log on to the SchedulerX console.

  2. In the left-side navigation pane, click Application Management.

  3. Find your application and click Access configuration in the Operation column.

If you have not created an application in SchedulerX yet, create one before proceeding.

Choose how to register jobs

After enabling takeover, register your Spring jobs in SchedulerX through one of two methods:

OptionBest forHow
Auto-sync (recommended)Large number of existing @Scheduled jobsAdd configuration properties (see below)
Manual creationSelective control over individual jobsCreate each job in the SchedulerX console

Option A: Auto-sync existing jobs (recommended)

To automatically synchronize all @Scheduled jobs to SchedulerX, add these properties:

# Enable automatic job synchronization
spring.schedulerx2.task.scheduling.sync=true
spring.schedulerx2.regionId=<region-id>
spring.schedulerx2.aliyunAccessKey=<your-access-key>
spring.schedulerx2.aliyunSecretKey=<your-secret-key>

Replace the placeholders with your actual values:

PlaceholderDescriptionExample
<region-id>The region where your SchedulerX instance runs. See Endpoints.cn-hangzhou
<your-access-key>Your Alibaba Cloud AccessKey IDLTAI5tXxx
<your-secret-key>Your Alibaba Cloud AccessKey SecretxXxXxXx
Important

Auto-synchronized jobs default to Broadcast run, where every worker node runs the job simultaneously -- matching native Spring behavior. If a job should run on only one node, change its Execution mode to Stand-alone operation in the console.

Option B: Manually create jobs

To register jobs individually, create each job in the console:

  1. Log on to the SchedulerX console.

  2. In the left-side navigation pane, click Task Management.

  3. On the Task Management page, click Create task.

  4. Set Task type to SpringSchedule, then configure the remaining parameters.

Job parameters
ParameterDescription
Task nameName for the job.
DescriptionBrief description for search and management.
Application IDApplication group the job belongs to. Select from the drop-down list.
Task typeJob type. Set to SpringSchedule for Spring jobs. Other valid values: Java, Shell, Python, Golang, Http, Node.js, XXL-JOB, DataWorks.
spring scheduleConfigurationFully qualified class name and method name of the job.
Execution modeHow the job runs across the cluster. Stand-alone operation: one random worker runs the job. Broadcast run: all workers run the job simultaneously.
PriorityExecution order when multiple jobs in the same application trigger simultaneously. Higher-priority jobs run first. For cross-worker priority guarantees, see Preemptible queues.
Task parametersOptional string passed to the job through the execution context.
Trigger frequency
The schedule set in the SchedulerX console takes precedence over @Scheduled annotations in your code. The annotations remain in the source but do not control execution timing.
ParameterDescription
Time typenone: triggered by a workflow. cron: scheduled with a cron expression. api: triggered by an API call. fixed_rate: triggered at a fixed interval (> 60 seconds). second_delay: triggered with a 1--60 second delay. one_time: triggered once at a specific time.
cron expressionCron expression for scheduling. Enter manually or use the built-in generator.
Fixed frequencyInterval in seconds. Available only when Time type is fixed_rate. The value must be greater than 60.
Fixed delayDelay in seconds (1--60). Available only when Time type is second_delay.
Advanced timing parameters
ParameterDescription
Time offsetOffset between the data timestamp and job trigger time. Retrieved from the execution context at runtime.
Time zoneTime zone for scheduling. Select a country/region or GMT offset.
CalendarBusiness calendar type: Workday or Financial day.
  1. Configure alert conditions and notification methods. For details, see Notification contacts and notification contact groups.

Verify the connection

  1. Start your Spring Boot application.

  2. Log on to the SchedulerX console.

  3. In the left-side navigation pane, click Application Management.

  4. Check the Total number of instances column for your application. A value greater than 0 confirms the connection.

Application Management page showing connected instances
  1. In the left-side navigation pane, click Task Management.

  2. Find your job and click Run once in the Operation column.

  3. Verify that the job runs successfully.

After verification, SchedulerX provides enterprise-level capabilities for your Spring jobs, including visualized management and control, log queries, execution chain tracing, and alerting.

FAQ

Why does the original Spring timer still run after SchedulerX takes over scheduled Spring jobs?

If a custom scheduler is specified in your application, SchedulerX overwrites the custom scheduler. Check whether the class that implements the org.springframework.scheduling.annotation.SchedulingConfigurer interface exists in your application project, and whether the setScheduler method of ScheduledTaskRegistrar is called to overwrite the default scheduler. If the class exists or the default scheduler is overwritten, comment out the related code.

How do I obtain the context for a Spring job?

Add the following code to your application project code to obtain the context:

JobContext jobContext = ContainerFactory.getContainerPool().getContext();

Does a Spring job return a processing result?

If the agent version is later than 1.10.11, Spring jobs can return processing results. The processing results are returned based on the specified scheduling methods.

@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..");
    }
    return new ProcessResult(true, "Processing result");
}

@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";
}

The original Spring scheduler still runs after takeover

This happens when your application defines a custom scheduler. Check whether any class implements org.springframework.scheduling.annotation.SchedulingConfigurer and calls setScheduler on ScheduledTaskRegistrar. If so, comment out that code -- SchedulerX cannot overwrite a custom scheduler.

Get the execution context

Retrieve the JobContext through ContainerFactory:

JobContext jobContext = ContainerFactory.getContainerPool().getContext();

Return a processing result

Requires agent version later than 1.10.11. Two return types are supported:

Return a ProcessResult with a status flag and a 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..");
    }
    return new ProcessResult(true, "Processing result");
}

Return a plain String:

@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";
}