springboot Integrates Distributed Task Scheduling xxl-job

This demo demo mainly demonstrates how Spring Boot integrates XXL-JOB to implement distributed timer tasks, and provides methods to bypass xxl-job-admin's management of timer tasks, including timer task list, trigger list, new timer tasks, delete timer tasks, stop timer tasks, start timer tasks, modify timer tasks, and trigger timer tasks manually.

xxl-job-admin dispatch center

  • Clone Dispatch Center Code

    $ git clone https://github.com/xuxueli/xxl-job.git

  • Modify application.properties

  server.port=8084
  spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_job?Unicode=true&characterEncoding=UTF-8&useSSL=false
  spring.datasource.username=root
  spring.datasource.password=root

Start xxl-job-admin Dispatch Center

Run XxlJobAdminApplication

Enter in browser: http://localhost:8084/xxl-job-admin

Default username password: admin/admin

Write Executor Project

pom.xml

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>com.xuxueli</groupId>
        <artifactId>xxl-job-core</artifactId>
        <version>2.1.2</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-commons -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-commons</artifactId>
        <version>2.1.1.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.7</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <!--Transform into API The way you want it-->
    <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-all</artifactId>
        <version>5.1.0</version>
    </dependency>
    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>28.2-jre</version>
    </dependency>

Write Configuration Class

  • XxlJobProps
/**
 * Created by haoxiaoyong on 2020/1/10 4:52 p.m.
 * e-mail: hxyHelloWorld@163.com
 * github:https://github.com/haoxiaoyong1014
 * Blog: www.haoxiaoyong.cn
 */
@Data
@ConfigurationProperties(prefix = "xxl.job")
public class XxlJobProps {

    /**
     * Dispatch Center Configuration
     */
    private XxlJobAdminProps admin;

    /**
     * Executor Configuration
     */
    private XxlJobExecutorProps executor;

    /**
     * accessToken interacting with dispatch center
     */
    private String accessToken;

    @Data
    public static class XxlJobAdminProps {
        /**
         * Dispatch Center Address
         */
        private String address;
    }
    @Data
    public static class XxlJobExecutorProps {
        /**
         * Executor name
         */
        private String appName;

        /**
         * Executor IP
         */
        private String ip;

        /**
         * Executor Port
         */
        private int port;

        /**
         * Executor Log
         */
        private String logPath;

        /**
         * Executor log retention days
         */
        private int logRetentionDays;
    }

}

  • configuration file
# web port
server:
  port: 8082

### xxl-job admin address list, such as "http://address" or "http://address01,http://address02"
xxl:
  job:
    # Executor communication TOKEN [optional]: Enabled when not empty;
    access-token:
    admin:
     # Dispatch Center Deployment and Address [optional]: Comma separated if there are multiple addresses in a Dispatch Center cluster deployment.Executors will use this address for "Executor Heart Rate Registration" and "Task Result Callback"; if blank, turn off automatic registration;
      address: http://127.0.0.1:8084/xxl-job-admin
    executor:
      # Executor AppName [optional]: executor heartbeat registration grouping basis; turn off automatic registration if blank
      app-name: xxl-job-executor-sample
      # Executor IP [optional]: blank default means automatic IP acquisition, specified IP can be set manually when multicard, the IP will not bind Host for communication purposes only; address information is used for Executor Registration and Dispatch Center Request and Trigger Tasks;
      ip:
      # Executor port number [optional]: less than or equal to 0 is obtained automatically; default port is 9999, when deploying multiple executors on a single machine, be careful to configure different executor ports;
      port: 9999
      # Executor Run Log File Storage Disk Path [Optional]: Requires read and write access to the path; uses the default path if empty;
      log-path: /data/applogs/xxl-job/jobhandler
      # Executor Log save days [optional]: Value greater than 3 will take effect, enable the periodic cleanup of executor Log files, otherwise it will not take effect;
      log-retention-days: 30

  • Writing the auto-assembly class JobConfig.java
@Slf4j
@Configuration
@EnableConfigurationProperties(XxlJobProps.class)
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class JobConfig {
    
    private final XxlJobProps xxlJobProps;
    private final InetUtils inetUtils;
    
    @Bean
    public XxlJobSpringExecutor xxlJobExecutor() {
        log.info(">>>>>>>>>>> xxl-job config init.");
        XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
        xxlJobSpringExecutor.setAdminAddresses(xxlJobProps.getAdmin().getAddress());
        xxlJobSpringExecutor.setAppName(xxlJobProps.getExecutor().getAppName());
        String ip = xxlJobProps.getExecutor().getIp();
        if (StringUtils.isBlank(ip)) {
            ip = inetUtils.findFirstNonLoopbackHostInfo().getIpAddress();
        }
        log.info("IP Address is: " + ip);
        log.info("AdminAddresses Address is: " + xxlJobProps.getAdmin().getAddress());
        xxlJobSpringExecutor.setIp(ip);
        xxlJobSpringExecutor.setPort(xxlJobProps.getExecutor().getPort());
        xxlJobSpringExecutor.setAccessToken(xxlJobProps.getAccessToken());
        xxlJobSpringExecutor.setLogPath(xxlJobProps.getExecutor().getLogPath());
        xxlJobSpringExecutor.setLogRetentionDays(xxlJobProps.getExecutor().getLogRetentionDays());
        return xxlJobSpringExecutor;
    }
}

Write specific timer logic TestJobHandler

@Component
public class TestJobHandler {

    @Autowired
    private InService inService;

    @XxlJob("jobHandler")
    public ReturnT<String> execute(String param) throws InterruptedException {
        for (int i = 0; i < 5; i++) {
            XxlJobLogger.log("beat at:" + i);
            TimeUnit.SECONDS.sleep(2);
        }

        inService.xxl();
       return ReturnT.SUCCESS;
    }
}
@Service
public class InService {

    public void xxl(){
        System.out.println("Hello World......");
    }

}

Start Executor JobApplication

  • Add Started Executor to Dispatch Center

    Executor Management - New Executors

  • Add Timed Tasks

    Task Management - New - Save

    The JobHandler here should match the value in the @XxlJob() comment;

  • Tap action, perform a task, console output Hello World...You can also view logs in the ui interface

Add Timed Tasks Using API

In a real-world scenario, adding a timer task requires manual operation in xxl-job-admin, which can be cumbersome. Users prefer to add timer task parameters, timer scheduling expressions on their own pages, and then add the timer task through API

Clone Dispatch Center Code

git clone https://github.com/xuxueli/xxl-job/

Modify xxl-job-admin

  • New in JobGroupController
	// Add Executor List
	@RequestMapping("/list")
	@ResponseBody
    // Remove Permission Check
	@PermissionLimit(limit = false)
	public ReturnT<List<XxlJobGroup>> list(){
		return  new ReturnT<>(xxlJobGroupDao.findAll());
	}
  • Modify JobInfoController

    // Add annotations on pageList, add, update, remove, pause, start, triggerJob methods to remove permission checks
    @PermissionLimit(limit = false)
    

Retrofit Executor Project

  • Add Manual Trigger Class

    /**
     * Created by haoxiaoyong on 2020/1/11 3:39 p.m.
     * e-mail: hxyHelloWorld@163.com
     * github:https://github.com/haoxiaoyong1014
     * Blog: www.haoxiaoyong.cn
     */
    @Slf4j
    @RestController
    @RequestMapping("/xxl-job")
    @RequiredArgsConstructor(onConstructor_ = @Autowired)
    public class ManualOperateController {
        private final static String baseUri = "http://127.0.0.1:8084/xxl-job-admin";
        private final static String JOB_INFO_URI = "/jobinfo";
        private final static String JOB_GROUP_URI = "/jobgroup";
    
        /**
         * Task group list, xxl-job is called trigger list
         */
        @GetMapping("/group")
        public String xxlJobGroup() {
            HttpResponse execute = HttpUtil.createGet(baseUri + JOB_GROUP_URI + "/list").execute();
            log.info("[execute]= {}", execute);
            return execute.body();
        }
    
        /**
         * Paging Task List
         *
         * @param page Current Page, First Page - > 0
         * @param size Number of bars per page, default 10
         * @return Paging Task List
         */
        @GetMapping("/list")
        public String xxlJobList(Integer page, Integer size) {
            Map<String, Object> jobInfo = Maps.newHashMap();
            jobInfo.put("start", page != null ? page : 0);
            jobInfo.put("length", size != null ? size : 10);
            jobInfo.put("jobGroup", 2);
            jobInfo.put("triggerStatus", -1);
    
            HttpResponse execute = HttpUtil.createGet(baseUri + JOB_INFO_URI + "/pageList").form(jobInfo).execute();
            log.info("[execute]= {}", execute);
            return execute.body();
        }
    
        /**
         * Test Manual Save Task
         */
        @GetMapping("/add")
        public String xxlJobAdd() {
            Map<String, Object> jobInfo = Maps.newHashMap();
            jobInfo.put("jobGroup", 2);
            jobInfo.put("jobCron", "0 0/1 * * * ? *");
            jobInfo.put("jobDesc", "Manually added tasks");
            jobInfo.put("author", "admin");
            jobInfo.put("executorRouteStrategy", "ROUND");
            jobInfo.put("executorHandler", "demoTask");
            jobInfo.put("executorParam", "Parameters for manually added tasks");
            jobInfo.put("executorBlockStrategy", ExecutorBlockStrategyEnum.SERIAL_EXECUTION);
            jobInfo.put("glueType", GlueTypeEnum.BEAN);
    
            HttpResponse execute = HttpUtil.createGet(baseUri + JOB_INFO_URI + "/add").form(jobInfo).execute();
            log.info("[execute]= {}", execute);
            return execute.body();
        }
    
        /**
         * Test triggers a task manually
         */
        @GetMapping("/trigger")
        public String xxlJobTrigger() {
            Map<String, Object> jobInfo = Maps.newHashMap();
            jobInfo.put("id", 5);
            jobInfo.put("executorParam", JSONUtil.toJsonStr(jobInfo));
    
            HttpResponse execute = HttpUtil.createGet(baseUri + JOB_INFO_URI + "/trigger").form(jobInfo).execute();
            log.info("[execute]= {}", execute);
            return execute.body();
        }
    
        /**
         * Test Manual Delete Task
         */
        @GetMapping("/remove")
        public String xxlJobRemove() {
            Map<String, Object> jobInfo = Maps.newHashMap();
            jobInfo.put("id", 4);
    
            HttpResponse execute = HttpUtil.createGet(baseUri + JOB_INFO_URI + "/remove").form(jobInfo).execute();
            log.info("[execute]= {}", execute);
            return execute.body();
        }
    
        /**
         * Test Manual Stop Task
         */
        @GetMapping("/stop")
        public String xxlJobStop() {
            Map<String, Object> jobInfo = Maps.newHashMap();
            jobInfo.put("id", 4);
    
            HttpResponse execute = HttpUtil.createGet(baseUri + JOB_INFO_URI + "/stop").form(jobInfo).execute();
            log.info("[execute]= {}", execute);
            return execute.body();
        }
    
        /**
         * Test Manual Start Task
         */
        @GetMapping("/start")
        public String xxlJobStart() {
            Map<String, Object> jobInfo = Maps.newHashMap();
            jobInfo.put("id", 4);
    
            HttpResponse execute = HttpUtil.createGet(baseUri + JOB_INFO_URI + "/start").form(jobInfo).execute();
            log.info("[execute]= {}", execute);
            return execute.body();
        }
    }
    
    

test

Take the example of triggering a task manually

  • Start xxl-job-admin

  • Start Executor Project

  • Access localhost:8082/xxl-job/trigger

  • console log

Extension: Build dispatch centers using Docker mirroring

Use docker mirroring to deploy xxl-job-admin;

Attach the execution script: xxl-job.sh

You can also type directly in the command window without using a script:

docker run -d --rm  -e PARAMS="--spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_job?Unicode=true&characterEncoding=UTF-8 --spring.datasource.use
rname=root --spring.datasource.password=123456"  -p 8680:8080  --name xxl-job-admin xuxueli/xxl-job-admin:2.1.1

Configure the database name and password!

51 original articles published. 45% praised. 140,000 visits+
Private letter follow

Tags: Spring github git Docker

Posted on Sun, 12 Jan 2020 20:49:38 -0500 by bigsid