All Products
Search
Document Center

Microservices Engine:Build and connect Java, Go, and Python applications from scratch

Last Updated:Mar 10, 2026

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.

Architecture diagram

Task execution modes

SchedulerX (XXL-JOB Edition) supports two execution modes. Choose the mode that fits your workload before you start development:

ModeBehavior
Single-instanceOne executor is selected from all executors based on the routing policy to perform an idempotent execution
Sharding broadcastThe 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

Step 1: Create an application

  1. Log on to the MSE XXL-JOB console and select a region.

  2. Click the target instance to open its details page. In the left-side navigation pane, click Application Management, then click Create Application.

  3. 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:

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:

PropertyDescriptionWhere to get the value
xxl.job.admin.addressesAdmin server URL for heartbeat registration and task callbacksConnection Configuration in the console
xxl.job.accessTokenAuthentication token for executor-admin communicationConnection Configuration in the console
xxl.job.executor.appnameExecutor group name; must match the AppName in the consoleValue you entered in Step 1
xxl.job.executor.addressExecutor addressConnection Configuration in the console
xxl.job.executor.ipExecutor IPSet manually if needed
xxl.job.executor.portPort the executor listens on (default: 9999)Set manually if 9999 is unavailable
xxl.job.executor.logpathLocal directory for task execution logsSet manually
xxl.job.executor.logretentiondaysNumber of days to retain log filesSet 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:

OptionDescriptionWhere to get the value
ServerAddrAdmin server URLConnection Configuration in the console
AccessTokenAuthentication tokenConnection Configuration in the console
ExecutorPortPort the executor listens on (default: 9999)Set manually if 9999 is unavailable
RegistryKeyExecutor nameValue you entered in Step 1
SetLoggerCustom 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:

ParameterDescriptionWhere to get the value
xxl_admin_baseurlAdmin server API URLConnection Configuration in the console
executor_app_nameExecutor group name; must match the AppName in the consoleValue you entered in Step 1
access_tokenAuthentication tokenConnection 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).

Important

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.1

3. 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:

Connection configuration screenshot
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=xxxxxxx

Step 3: Verify the deployment

Verify the executor connection

  1. In the MSE console, open the instance details page. In the left-side navigation pane, click Application Management.

  2. On the application list page, click the number in the executors column for your application to view connected executor addresses and their online status.

Executor connection verification

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.

  1. In the left-side navigation pane, click Task Management, then click Create Task.

  2. Complete the basic configuration: Single-instance task configuration

    • Task Name: Enter a descriptive name.

    • JobHandler Name: Enter the handler name registered in your code (for example, helloworld for Java, task.test for Go, or demoJobHandler for Python).

    • Associated Application: Select your application.

    • Routing Policy: Select Polling.

    • Click Next.

  3. Configure the schedule: Schedule configuration

    • 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.

  4. Configure Notifications (timeout alarms, success notifications, failure alarms). Use the defaults or customize as needed, then click Next.

    Notifications configuration

  5. 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.

    Run Once dialog

  6. Click More > Scheduling Records to view execution records.

  7. In the left-side navigation pane, click Execution List. In the Actions column for the target record, click Log to view execution logs.

    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.

  1. In the left-side navigation pane, click Task Management, then click Create Task.

  2. Complete the basic configuration: Sharding broadcast task configuration

    • Task Name: Enter a descriptive name.

    • JobHandler Name: Enter the sharding handler name (for example, task.shardingTest for Go).

    • Associated Application: Select your application.

    • Routing Policy: Select Sharded Broadcast.

    • Click Next.

  3. Configure the schedule: Sharding task 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.

  4. Configure Notifications as needed, then click Next.

    Notifications configuration

  5. 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.

    Sharding Run Once dialog

  6. Click More > Scheduling Records to view execution records.

  7. 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.

    Shard details

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

    Shard logs