【全链路】基于XxlJob-动态添加定时任务

789 阅读3分钟

1. 背景

全链路监控不同的规则执行频率不同。

  • p0级别规则要求几乎没有延迟,那么可能 1/2 两分钟执行一次

  • 有些规则可能一天执行一次,比如按照供应商 / 业务线维度的日报(推送各种指标值),比如每天推送IM坐席好评数据,问题解决数等

所以创建规则的时候需要制定规则执行周期,也就是需要给XxlJob动态添加一个定时任务。XxlJob添加定时任务都需要去 admin 后台通过图形化的界面添加。现在想要达成的效果就是,添加/修改的规则的时候,会往XxlJob动态地添加/修改定时任务。

2. 实现

在xxljob-admin项目中,有一个JobInfoController, 这个类就是处理各种新增任务,修改任务,触发任务的Controller,

image.png

但是有个问题就是,这些接口都是后台使用的,要想调用,就必须得登录才行,不登录是没有办法访问的。那怎么办?其实模拟浏览器的登录态即可。第一次登录会返回一个 cookie,后面各种操作都携带上这个cookie,就可以完成 xxl-job-client 动态地添加,删除,启动,暂停任务.....

@Component
@Slf4j
public class LoginClient {

    @Getter
    private String COOKIE = "";
    private final XxlJobClientConfigProperties clientConfigProperties;

    public LoginClient(XxlJobClientConfigProperties clientConfigProperties) {
        this.clientConfigProperties = clientConfigProperties;
    }

    @PostConstruct
    public void init() {
        val cookies = getPostCookies(clientConfigProperties.getLoginUrl());
        if (isNull(cookies)) {
            log.error("xxlJob 登录失败");
        } else {
            val tmpCookies = new StringBuilder();
            for (Cookie c : cookies) {
                tmpCookies.append(c.toString()).append(";");
            }
            COOKIE = tmpCookies.toString();
            log.info("xxlJob 登录成功");
        }
    }
}

针对动态操作定时任务的一些API;

  1. 新增定时任务 (添加规则的时候调用)
  2. 修改定时任务 (修改规则执行周期的时候调用)
  3. 删除定时任务 (删除规则的时候调用)
  4. 暂停/开启定时任务 (暂停/启动规则的时候调用)

image.png

3. 其他的实现方式

xxl-job其实中已经为我们提供了一个口子,就是一个注解和一个拦截器,通过这个注解可以配置接口是否可以跳过登录进行访问。也就是我们可以把接口配置成跳过登录验证进行访问就可以了,这样我们就能不登录而进行请求 。这个注解就是 @PermissionLimit(limit = false) ,默认是true,也就是需要做登录验证。

好了有了这个注解就好办了,但是这里要注意,我们最好不要直接把这个注解配置到刚才截图中的对任务的操作的方法上,因为这些方法都是通过后台调用的,也就是对于操作者这些接口是可见的,如果打开了他们的权限,其实对于接口是有威胁的。所以我们可以自己扩展几个接口,保留原接口不变。那么我们直接在JobInfoController中添加几个方法

/*------------------自定义方法----------------------  */
@RequestMapping("/addJob")
@ResponseBody
@PermissionLimit(limit = false)
public ReturnT<String> addJobInfo(@RequestBody XxlJobInfo jobInfo) {
return xxlJobService.add(jobInfo);
}

@RequestMapping("/updateJob")
@ResponseBody
@PermissionLimit(limit = false)
public ReturnT<String> updateJobCron(@RequestBody XxlJobInfo jobInfo) {
return xxlJobService.updateCron(jobInfo);
}

@RequestMapping("/removeJob")
@ResponseBody
@PermissionLimit(limit = false)
public ReturnT<String> removeJob(@RequestBody XxlJobInfo jobInfo) {
return xxlJobService.remove(jobInfo.getId());
}

@RequestMapping("/pauseJob")
@ResponseBody
@PermissionLimit(limit = false)
public ReturnT<String> pauseJob(@RequestBody XxlJobInfo jobInfo) {
return xxlJobService.stop(jobInfo.getId());
}

@RequestMapping("/startJob")
@ResponseBody
@PermissionLimit(limit = false)
public ReturnT<String> startJob(@RequestBody XxlJobInfo jobInfo) {
return xxlJobService.start(jobInfo.getId());
}

@RequestMapping("/addAndStart")
@ResponseBody
@PermissionLimit(limit = false)
public ReturnT<String> addAndStart(@RequestBody XxlJobInfo jobInfo) {
ReturnT<String> result = xxlJobService.add(jobInfo);
int id = Integer.valueOf(result.getContent());
xxlJobService.start(id);
return result;
}

这种方式的特点是,不需要再写一个xxljob客户端去通过http请求获得cookie。但是需要修改xxlJob的源代码。各有各的优势

4. 总结

上面介绍了如何基于XxlJob动态添加定时任务。

  1. 通过模拟浏览器登录态,调用xxljob-admin提供的api来实现。
  2. 直接修改 xxljob-admin 源码。(建议使用这种方式!)

5. 源码

源码是通过 模拟浏览器登录态,调用xxljob-admin提供的api来实现。

xxl-job-client: 通过http请求动态创建xxljob任务,用于一些特定的场景。 (gitee.com)