If you run a self-hosted XXL-JOB cluster, you handle infrastructure maintenance, monitoring, and scaling on your own. SchedulerX (XXL-JOB Edition) is a fully managed alternative that is compatible with open source XXL-JOB SDKs. You can migrate your existing executors or build new ones to connect to the platform.
How it works
SchedulerX (XXL-JOB Edition) separates scheduling from execution:
Platform side (managed): The SchedulerX console handles cron scheduling, routing, monitoring, and alerting. No server infrastructure to manage.
Executor side (your code): Your application registers task handlers -- annotated methods (Java), registered functions (Go), or decorated functions (Python) -- and exposes them as named Beans or handlers. The platform invokes these handlers based on the schedule and routing policy you configure.

Task execution modes
SchedulerX (XXL-JOB Edition) supports two execution modes. Choose the mode that fits your workload before you start development:
| Mode | Behavior |
|---|---|
| Single-instance | One executor is selected from all executors based on the routing policy to perform an idempotent execution |
| Sharding broadcast | The task is broadcast to all executors; each receives a unique shard index for distributed batch processing |
Unlike open source XXL-JOB, SchedulerX (XXL-JOB Edition) aggregates and displays the status of all shards for each execution.
Prerequisites
A Resource Access Management (RAM) user with the required permissions for XXL-JOB. See Authorize SchedulerX (XXL-JOB Edition)
An XXL-JOB instance. See Create an instance
Step 1: Create an application
Log on to the MSE XXL-JOB console and select a region.
Click the target instance to open its details page. In the left-side navigation pane, click Application Management, then click Create Application.
Enter an AppName and a Name. Keep the system-generated AccessToken and click OK.
Save the AppName and AccessToken values. You need them to configure the executor connection in Step 2.
Step 2: Develop and deploy the application
Develop an XXL-JOB task
SchedulerX (XXL-JOB Edition) supports Java, Go, and Python executors. Each language section below covers dependency setup, executor initialization, and a sample task handler.
For complete reference projects, see the open source demos:
Python: pyxxl
Java
1. Add the Maven dependency
Add xxl-job-core to your pom.xml. For the latest version, check the demo project.
<!-- xxl-job-core -->
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>2.2.x</version>
</dependency>2. Initialize the executor
Create a Spring configuration class that reads connection parameters from your application properties:
@Configuration
public class XxlJobConfig {
private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);
@Value("${xxl.job.admin.addresses}")
private String adminAddresses;
@Value("${xxl.job.accessToken}")
private String accessToken;
@Value("${xxl.job.executor.appname}")
private String appname;
@Value("${xxl.job.executor.address}")
private String address;
@Value("${xxl.job.executor.ip}")
private String ip;
@Value("${xxl.job.executor.port}")
private int port;
@Value("${xxl.job.executor.logpath}")
private String logPath;
@Value("${xxl.job.executor.logretentiondays}")
private int logRetentionDays;
@Bean
public XxlJobSpringExecutor xxlJobExecutor() {
logger.info(">>>>>>>>>>> xxl-job config init.");
XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
xxlJobSpringExecutor.setAppname(appname);
xxlJobSpringExecutor.setAddress(address);
xxlJobSpringExecutor.setIp(ip);
xxlJobSpringExecutor.setPort(port);
xxlJobSpringExecutor.setAccessToken(accessToken);
xxlJobSpringExecutor.setLogPath(logPath);
xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
return xxlJobSpringExecutor;
}
}The following table describes each configuration property:
| Property | Description | Where to get the value |
|---|---|---|
xxl.job.admin.addresses | Admin server URL for heartbeat registration and task callbacks | Connection Configuration in the console |
xxl.job.accessToken | Authentication token for executor-admin communication | Connection Configuration in the console |
xxl.job.executor.appname | Executor group name; must match the AppName in the console | Value you entered in Step 1 |
xxl.job.executor.address | Executor address | Connection Configuration in the console |
xxl.job.executor.ip | Executor IP | Set manually if needed |
xxl.job.executor.port | Port the executor listens on (default: 9999) | Set manually if 9999 is unavailable |
xxl.job.executor.logpath | Local directory for task execution logs | Set manually |
xxl.job.executor.logretentiondays | Number of days to retain log files | Set manually |
3. Write a task handler
The following example uses the version 2.2.x API. The @XxlJob annotation registers the method as a handler named helloworld, which you reference when creating a task in the console.
XXL-JOB APIs vary by version. Check the demo project for your version.
@Component
public class SampleXxlJob {
private static Logger logger = LoggerFactory.getLogger(SampleXxlJob.class);
@XxlJob("helloworld")
public ReturnT<String> helloworld(String param) throws Exception {
XxlJobLogger.log("XXL-JOB, Hello World, start...");
for (int i = 0; i < 5; i++) {
XxlJobLogger.log("beat at:" + i);
TimeUnit.SECONDS.sleep(2);
}
System.out.println("XXL-JOB, Hello World, finished");
return ReturnT.SUCCESS;
}
}Go
1. Install the SDK
Pull the Go SDK with the latest tag. For version details, see xxl-job-executor-go.
go get github.com/xxl-job/xxl-job-executor-go@{latest_tag}2. Initialize the executor and register task handlers
The following example initializes an executor, registers two task handlers (task.test and task.shardingTest), and sets up a custom log handler and middleware:
package main
import (
"context"
"fmt"
xxl "github.com/xxl-job/xxl-job-executor-go"
"github.com/xxl-job/xxl-job-executor-go/example/task"
"log"
)
func main() {
exec := xxl.NewExecutor(
xxl.ServerAddr("xxxxxx"), // Admin URL from Connection Configuration in the console
xxl.AccessToken("xxxxxxx"), // Access token from Connection Configuration in the console
xxl.ExecutorPort("9999"), // Default: 9999 (optional)
xxl.RegistryKey("golang-jobs"), // Executor name
xxl.SetLogger(&logger{}), // Custom logger (optional)
)
exec.Init()
exec.Use(customMiddleware)
// Set a custom log view handler
exec.LogHandler(customLogHandle)
// Register task handlers
exec.RegTask("task.test", task.Test)
exec.RegTask("task.shardingTest", task.ShardingTest)
log.Fatal(exec.Run())
}
// Custom log handler
func customLogHandle(req *xxl.LogReq) *xxl.LogRes {
return &xxl.LogRes{Code: xxl.SuccessCode, Msg: "", Content: xxl.LogResContent{
FromLineNum: req.FromLineNum,
ToLineNum: 2,
LogContent: "This is a custom log handler",
IsEnd: true,
}}
}
// Implements the xxl.Logger interface
type logger struct{}
func (l *logger) Info(format string, a ...interface{}) {
fmt.Println(fmt.Sprintf("Custom log - "+format, a...))
}
func (l *logger) Error(format string, a ...interface{}) {
log.Println(fmt.Sprintf("Custom log - "+format, a...))
}
// Custom middleware
func customMiddleware(tf xxl.TaskFunc) xxl.TaskFunc {
return func(cxt context.Context, param *xxl.RunReq) string {
log.Println("I am a middleware start")
res := tf(cxt, param)
log.Println("I am a middleware end")
return res
}
}The following table describes the key executor options:
| Option | Description | Where to get the value |
|---|---|---|
ServerAddr | Admin server URL | Connection Configuration in the console |
AccessToken | Authentication token | Connection Configuration in the console |
ExecutorPort | Port the executor listens on (default: 9999) | Set manually if 9999 is unavailable |
RegistryKey | Executor name | Value you entered in Step 1 |
SetLogger | Custom logger implementing the xxl.Logger interface (optional) | Your own implementation |
3. Write task handlers
package task
import (
"context"
"fmt"
xxl "github.com/xxl-job/xxl-job-executor-go"
)
func Test(cxt context.Context, param *xxl.RunReq) (msg string) {
fmt.Println("test one task" + param.ExecutorHandler + " param:" + param.ExecutorParams + " log_id:" + xxl.Int64ToStr(param.LogID))
return "test done"
}
func ShardingTest(cxt context.Context, param *xxl.RunReq) (msg string) {
fmt.Println("shardingId:" + xxl.Int64ToStr(param.BroadcastIndex) + ", shardingTotal:" + xxl.Int64ToStr(param.BroadcastTotal))
return "ShardingTest done"
}Python
1. Install the package
pip install pyxxl
# Optional: write logs to Redis
pip install "pyxxl[redis]"
# Optional: load configuration from .env files
pip install "pyxxl[dotenv]"
# Install all optional dependencies
pip install "pyxxl[all]"For version details, see pyxxl.
2. Write task handlers and start the executor
The following example configures the executor, registers two task handlers (one async, one sync), and starts the executor:
import asyncio
import time
from pyxxl import ExecutorConfig, PyxxlRunner
from pyxxl.ctx import g
config = ExecutorConfig(
xxl_admin_baseurl="http://xxljob-1b3fd81****.schedulerx.mse.aliyuncs.com/api/",
executor_app_name="your-app-name",
access_token="default_token",
# If the admin server can reach the executor directly, leave executor_listen_host empty.
# executor_listen_host="0.0.0.0",
)
app = PyxxlRunner(config)
@app.register(name="demoJobHandler")
async def test_task():
# Access task parameters through the global context object g
g.logger.info("get executor params: %s" % g.xxl_run_data.executorParams)
for i in range(10):
g.logger.warning("test logger %s" % i)
await asyncio.sleep(5)
return "Success..."
@app.register(name="sync_func")
def test_task4():
# Use g.logger for logs visible in the console (INFO level and above)
n = 1
g.logger.info("Job %s get executor params: %s" % (g.xxl_run_data.jobId, g.xxl_run_data.executorParams))
# For sync tasks with loops, check g.cancel_event in each iteration to support cancellation
while n <= 10 and not g.cancel_event.is_set():
g.logger.info(
"log to {} logger test_task4.{},params:{}".format(
g.xxl_run_data.jobId,
n,
g.xxl_run_data.executorParams,
)
)
time.sleep(2)
n += 1
return "Success 3"
if __name__ == "__main__":
app.run_executor()Replace the following placeholders with your actual values:
| Parameter | Description | Where to get the value |
|---|---|---|
xxl_admin_baseurl | Admin server API URL | Connection Configuration in the console |
executor_app_name | Executor group name; must match the AppName in the console | Value you entered in Step 1 |
access_token | Authentication token | Connection Configuration in the console |
Deploy to Alibaba Cloud
SchedulerX (XXL-JOB Edition) operates on the Alibaba Cloud internal network only. Deploy your application to an Alibaba Cloud service such as Container Service for Kubernetes (ACK).
The ACK cluster must be in the same VPC as the SchedulerX (XXL-JOB Edition) instance.
The following example deploys a Java Spring Boot application to ACK:
1. Create a Dockerfile
In the root directory of your Spring Boot project, create a Dockerfile:
# Replace with your own base image
FROM reg.docker.alibaba-inc.com/xxx/xxxx-java:1.0-beta
MAINTAINER your-name
ENV JAVA_OPTS=""
ADD target/xxl-job-executor-sample-springboot-*.jar /app.jar
ENTRYPOINT ["sh","-c","java -jar $JAVA_OPTS /app.jar]2. Build and push the Docker image
Build the image and push it to Container Registry (ACR):
docker login --username=<your-username> registry.cn-hangzhou.aliyuncs.com --password=<your-password>
docker buildx build --platform linux/amd64 -t schedulerx-registry.cn-hangzhou.cr.aliyuncs.com/schedulerx3/xxljob-demo:2.4.1 .
docker push schedulerx-registry.cn-hangzhou.cr.aliyuncs.com/schedulerx3/xxljob-demo:2.4.13. Get the connection configuration
In the MSE console, go to Application Management. In the Actions column for your application, click Connection Configuration. Copy the connection parameters for use in the deployment YAML.
4. Deploy to ACK
Log on to the ACK console and navigate to the target cluster. In the left-side navigation pane, choose Configuration Management > ConfigMaps, and click Create from YAML.
This example uses connection type 2 (JVM parameters injected as environment variables via the -D flag). Replace the JAVA_OPTS value with the parameters from the connection configuration:

apiVersion: apps/v1
kind: Deployment
metadata:
name: xxljob-xueren-test
labels:
app: xxljob-xueren-test
spec:
replicas: 2
selector:
matchLabels:
app: xxljob-xueren-test
template:
metadata:
labels:
app: xxljob-xueren-test
spec:
containers:
- name: xxljob-executor
image: schedulerx-registry.cn-hangzhou.cr.aliyuncs.com/schedulerx3/xxljob-demo:2.4.1
ports:
- containerPort: 9999
env:
- name: JAVA_OPTS
value: >-
-Dxxl.job.admin.addresses=http://xxljob-xxxxx.schedulerx.mse.aliyuncs.com
-Dxxl.job.executor.appname=xueren_test
-Dxxl.job.accessToken=xxxxxxxStep 3: Verify the deployment
Verify the executor connection
In the MSE console, open the instance details page. In the left-side navigation pane, click Application Management.
On the application list page, click the number in the executors column for your application to view connected executor addresses and their online status.

Test a single-instance task
A single-instance task selects one executor per trigger based on the routing policy (for example, polling) and runs the task once.
In the left-side navigation pane, click Task Management, then click Create Task.
Complete the basic configuration:

Task Name: Enter a descriptive name.
JobHandler Name: Enter the handler name registered in your code (for example,
helloworldfor Java,task.testfor Go, ordemoJobHandlerfor Python).Associated Application: Select your application.
Routing Policy: Select Polling.
Click Next.
Configure the schedule:

Set Time Type to cron.
Click Use Generator to build a Cron Expression. For example,
0 0 12 * * ?runs the task daily at 12:00.Click Next.
Configure Notifications (timeout alarms, success notifications, failure alarms). Use the defaults or customize as needed, then click Next.

After the task is created, click Run Once in the Actions column. In the dialog box, optionally select Specify a Machine and configure Instance Parameters, then click OK.

Click More > Scheduling Records to view execution records.
In the left-side navigation pane, click Execution List. In the Actions column for the target record, click Log to view execution logs.

Test a sharding broadcast task
A sharding broadcast task sends the task to all executors simultaneously. Each executor receives a unique shard index (BroadcastIndex) and the total shard count (BroadcastTotal) for distributed batch processing.
In the left-side navigation pane, click Task Management, then click Create Task.
Complete the basic configuration:

Task Name: Enter a descriptive name.
JobHandler Name: Enter the sharding handler name (for example,
task.shardingTestfor Go).Associated Application: Select your application.
Routing Policy: Select Sharded Broadcast.
Click Next.
Configure the schedule:

Set Time Type to cron.
Click Use Generator to build a Cron Expression. For example,
0 10 * * * ?runs at the 10th minute of every hour.Click Next.
Configure Notifications as needed, then click Next.

After the task is created, click Run Once in the Actions column. In the dialog box, optionally select Specify a Machine and configure Instance Parameters, then click OK.

Click More > Scheduling Records to view execution records.
In the left-side navigation pane, click Execution List. In the Actions column for the target record, click Details. The Shard Details section shows the aggregated execution status for each executor.

For each shard, click Log in the Actions column to view execution logs.
