preface

Task scheduling is a component commonly used in Java projects, which can specify when a task is triggered. The most familiar component is Quartz in the Spring framework. Some popular distributed scheduling components, such as Elastic – Job/Azkaban, are developed based on Quartz Task scheduler xxL-job.

Project introduction

XXL – the job is a very easy to learn to fit lightweight open source distributed scheduling framework, divided into the management end and execute end two pieces, responsible for configuration management end task information and view the task execution logs, perform side only need to configure and manage the connection information to specific task logic developed, the current version is continuing iteration, simple to use and powerful, See the official introduction for specific functions and features. Without further ado, let’s get right to the action.

In actual combat

1. Deploy the server

Download from the https://github.com/xuxueli/xxl-job project, using Navicat mysql client tools perform project root directory doc/db/table_xxl_job. SQL file, library name themselves able to modify, a total of eight tables, as follows:

Create a new Spring Boot project, copy the downloaded files in xxl-job-admin directory and pom. XML file to the new project (if you do not want to create a new project, you can directly use the downloaded project to modify deployment), modify the database connection information in application.

image-20200603145447639

Pom. XML dependency xxl-job-core version 2.2.0

image-20200603150900339

Modify the log output path in logback. XML.

Well, more than 3 steps to fix the server configuration, start the project, and access http://localhost:8080/xxl-job-admin/, the default administrator account admin / 123456 to log in.

This interaction, yes, isn’t it interesting?

2. Configure on the execution end

To create a new Module, you need to modify logback. XML and add xxl-job-core dependencies to pom.xml, as on the server.

To simulate the distributed effect, xiaobian creates two configuration files to distinguish between the two executing services.

application-9998.properties

# web port
server.port=8081
# no web
#spring.main.web-environment=false
# log config
logging.config=classpath:logback.xml

### xxl-job admin address list, such as "http://address" or "http://address01,http://address02"XXL. Job. Admin. Addresses = http://127.0.0.1:8080/xxl-job-admin### xxl-job, access token
xxl.job.accessToken=

### xxl-job executor appname
xxl.job.executor.appname=my-job-executor
### xxl-job executor registry-address: default use address to registry , otherwise use ip:port if address is null
xxl.job.executor.address=
### xxl-job executor server-info
xxl.job.executor.ip=
xxl.job.executor.port=9998
### xxl-job executor log-path
xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
### xxl-job executor log-retention-days
xxl.job.executor.logretentiondays=30

Copy the code

application-9999.properties

# web port
server.port=8082
# no web
#spring.main.web-environment=false

# log config
logging.config=classpath:logback.xml

### xxl-job admin address list, such as "http://address" or "http://address01,http://address02"XXL. Job. Admin. Addresses = http://127.0.0.1:8080/xxl-job-admin### xxl-job, access token
xxl.job.accessToken=

### xxl-job executor appname
xxl.job.executor.appname=my-job-executor
### xxl-job executor registry-address: default use address to registry , otherwise use ip:port if address is null
xxl.job.executor.address=
### xxl-job executor server-info
xxl.job.executor.ip=
xxl.job.executor.port=9999
### xxl-job executor log-path
xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
### xxl-job executor log-retention-days
xxl.job.executor.logretentiondays=30
Copy the code

Port is different from xxl.job.executor. Port. The executor service, like Spring Boot, has built-in Tomcat and also exposes a port registered with the server for high availability load.

Create a Java Config class and define an XxlJobSpringExecutor execution class that uses the configuration, as follows

@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;
    }
Copy the code

Configure two boot configurations and start them separately. The result is as follows:

Start the two services perfectly and check whether the server platform has the registration information of these two services.

Note: For demonstration purposes, an executor has been created and AppName must be the same as xxl.job.executor.appName in the configuration file.

3. Task development

3.1 Method-based annotation task

Without further ado, get straight to the code. After all, code is the best way for programmers to communicate.

*/ @xxljob (value = value)"myJobAnnotationHandler",init = "init", destroy = "destroy")
    public ReturnT<String> myJobAnnotationHandler(String param) throws Exception {
        XxlJobLogger.log("XXL-JOB-ANNOTATION, myJobAnnotationHandler.");

        log.info("my first annotation job run, param: {},port:{}",param,port);

        return ReturnT.SUCCESS;
    }
    
    public void init(){
        log.info("my annotation job init");
    }

    public void destroy(){
        log.info("my job annotation job destory");
    }
Copy the code

3.2 API-based Tasks

@Slf4j public class ApiJob extends IJobHandler { @Override public ReturnT<String> execute(String param) throws Exception  { XxlJobLogger.log("XXL-JOB-API, Hello World.");

        log.info("my job api run, param: {}",param);

        returnReturnT.SUCCESS; }}Copy the code
 @PostConstruct
    public void registerHandler(){
   XxlJobExecutor.registJobHandler("myJobApiHandler",new ApiJob());
    }
Copy the code

3.3 Fragment Broadcast Task

/** ** */ @xxljob ("myShardJobAnnotationHandler")
    public ReturnT<String> myShardJobAnnotationHandler(String param) throws Exception {
        XxlJobLogger.log("XXL-JOB-ANNOTATION, myShardJobAnnotationHandler.");

        log.info("my shard job run, param: {}",param);
        ShardingUtil.ShardingVO shardingVO = ShardingUtil.getShardingVo();
        log.info("Shard parameter: Current shard number = {}, total shard number = {}", shardingVO.getIndex(), shardingVO.getTotal()); // Business logicfor (int i = 0; i < shardingVO.getTotal(); i++) {
            if (i == shardingVO.getIndex()) {
                log.info({} slice, hit fragment start processing, i);
            } else {
                log.info("{} slice, ignore", i); }}return ReturnT.SUCCESS;
    }
Copy the code

Above is a more practical way to organize the task creation, I prefer the annotation form, add a comment to the method is done.

4. Task execution

All that’s left is silly interface manipulation. Let’s go.

4.1 Single Task Execution

Create a routing strategy for polling tasks, specify how expression, and fill in the JobHandler myJobAnnotationHandler, myJobAnnotationHandler is spring IOC container management bean name, interested in children’s shoes can look at the source.

To demonstrate the effect, click Execute once and enter the task parameters.

Polling the invoke executor service results in the following:

4.2 Sub-Task Execution

Update the task and specify the subtask ID as 5. Separate multiple subtasks with commas

The result is as follows

4.3 Fragment Broadcast Task Execution

A sharding task is a broadcast function. Each time it is triggered, each business execution class that executes the service is called, similar to how different consumer groups in Kafka consume the same topic.

The result is as follows

It’s too aggressive and needs to refresh the configuration information in the project periodically, which is perfect.

5. Task logs

The task log is an important part of the task history to track problems and correct lost business data

You can view the scheduling remarks. The parent and child task scheduling information is very detailed. You can view the execution status of subtasks by executing the remarks

Look at the console output, where the logs are printed out by the XxlJobLogger class in the executor

The code for

**1. Visit: **github.com/pengziliu/G…

2. Click on the lower left to read the original article

conclusion

Xxl-job has many other features, such as task timeout control, task failure retry, task failure alarm, and email alarm. These functions are closely related to business and can effectively avoid production accidents and prevent loss.

Compared with the previously used task scheduling components, XXL-Job decouples task scheduling and execution, greatly improving availability and expansibility. The code is almost non-invasive, which is very consistent with the concept of spring Boot without configuration and out of the box. The visual operation of the task scheduling platform is really awesome, and it feels like small white people can use it.