Spring@Scheduled定时任务接入XXL-JOB的一种方案(基于SC Gateway)

这篇具有很好参考价值的文章主要介绍了Spring@Scheduled定时任务接入XXL-JOB的一种方案(基于SC Gateway)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

背景

目前在职的公司,维护着Spring Cloud分布式微服务项目有25+个。其中有10个左右微服务都写有定时任务逻辑,采用Spring @Scheduled这种方式。

Spring @Scheduled定时任务的缺点:

  1. 不支持集群:为避免重复执行,需引入分布式锁
  2. 死板不灵活:不支持手动执行,单次执行,补偿执行,修改任务参数,暂停任务,删除任务,修改调度时间,失败重试
  3. 无报警机制:任务失败之后没有报警机制,逻辑执行异常记录ERROR日志接入Prometheus告警这种方式不算,这算是日志层面的告警,而不是任务层面的告警机制
  4. 不支持分片任务:处理有序数据时,多机器分片执行任务处理不同数据
  5. ……

基于此,考虑引入轻量级分布式定时调度框架XXL-JOB,即把定时任务迁到XXL-JOB平台。

关于XXL-JOB,可参考之前的blog。

设计方案

考虑到我们有10+个SC分布式应用,30+个定时任务。如果每个应用都需要迁移改造的话,则每个应用都需要配置XXL-JOB相关的信息。当然,这可以通过Apollo namespace共享继承机制来实现。题外话:有空的话,后面会写一篇Apollo namespace配置继承的blog。

也就是说,我可以在一个应用里(一个应用对应着一个Apollo namespace)的Apollo里维护好XXL-JOB的配置信息,其他应用通过复用此应用(的Apollo)来实现配置复用。

但是每个应用还得新增一个配置类,配置类怎么实现复用呢?这也能解决。解决方案就是在commons组件库里维护配置类(需要引入Spring @Configuration注解,即引入spring-context依赖包),然后每个应用的Spring Boot启动类里需要扫描到此配置类。

还得改造一下30+个定时任务对应的30+个@@Component定时任务类,所有的定时任务应用都需要引入maven依赖。

还得手动在XXL-JOB里新增定时任务类。

看起来还不错的方案,但是不排除不同的应用有同名的配置,遇到同名的配置,则需要修改配置命名。Spring Boot启动类改造可能会带来未知的问题。

最后的最后,考虑到我们所有的应用都需要经过Gateway网关服务来转发,不管是对内的应用,还是对外的应用,对外的应用有包括C端,B端,和第三方客户。故而有下面的最终方案。

实现方案

在对内的网关应用里,引入maven依赖:

<dependency>
    <groupId>com.xuxueli</groupId>
    <artifactId>xxl-job-core</artifactId>
    <version>2.4.0</version>
</dependency>

新增如下XXL-JOB配置类:

@Slf4j
@Configuration
public class XxlJobConfig {
    @Value("${xxl.job.admin.addresses}")
    private String adminAddresses;
    @Value("${xxl.job.executor.appname}")
    private String appName;
    @Value("${xxl.job.executor.port:9999}")
    private int port;
    @Value("${xxl.job.accessToken:default_token}")
    private String accessToken;

    @Bean
    public XxlJobSpringExecutor xxlJobExecutor() {
        log.info(">>>>>>>>>>> xxl-job config init.");
        XxlJobSpringExecutor executor = new XxlJobSpringExecutor();
        executor.setAdminAddresses(adminAddresses);
        executor.setAppname(appName);
        executor.setPort(port);
        executor.setAccessToken(accessToken);
        return executor;
    }
}

对应的,需要在Apollo里新增如下配置。其中有些配置是固定不变的,可以放在本地配置文件里;未来有可能变化的,放在Apollo里。
Spring@Scheduled定时任务接入XXL-JOB的一种方案(基于SC Gateway),Spring Cloud,gateway
这里的appname实际上就是XXL-JOB的执行器:
Spring@Scheduled定时任务接入XXL-JOB的一种方案(基于SC Gateway),Spring Cloud,gateway
gateway服务是以pod形式运行在k8s集群里,不言而喻,采用自动注册这种方式。

网关服务里新增定时任务解析,请求转发配置类:

@Slf4j
@Component
public class XxlJobLogicConfig {
	private static final String URL = "url:";
	private static final String METHOD = "method:";
	private static final String DATA = "data:";
	private static final String GET = "GET";
	private static final String POST = "POST";

    @XxlJob("httpJobHandler")
    public void httpJobHandler() {
    	// 参数解析及校验
        String jobParam = XxlJobHelper.getJobParam();
        if (StringUtils.isBlank(jobParam)) {
            XxlJobHelper.log("param[" + jobParam + "] invalid");
            XxlJobHelper.handleFail();
            return;
        }
        String[] httpParams = jobParam.split("\n");
        String url = "";
        String method = "";
        String data = "null";
        for (String httpParam : httpParams) {
            if (httpParam.startsWith(URL)) {
                url = httpParam.substring(httpParam.indexOf(URL) + URL.length()).trim();
            }
            if (httpParam.startsWith(METHOD)) {
                method = httpParam.substring(httpParam.indexOf(METHOD) + METHOD.length()).trim().toUpperCase();
            }
            if (httpParam.startsWith(DATA)) {
                data = httpParam.substring(httpParam.indexOf(DATA) + DATA.length()).trim();
            }
        }
        if (StringUtils.isBlank(url)) {
            XxlJobHelper.log("url[" + url + "] invalid");
            XxlJobHelper.handleFail();
            return;
        }
        if (!GET.equals(method) && !POST.equals(method)) {
            XxlJobHelper.log("method[" + method + "] invalid");
            XxlJobHelper.handleFail();
            return;
        }
        log.info("xxlJob调度请求url={},请求method={},请求数据data={}", url, method, data);
        // 判断是否为POST请求
        boolean isPostMethod = POST.equals(method);
        HttpURLConnection connection = null;
        BufferedReader bufferedReader = null;
        try {
            URL realUrl = new URL(url);
            connection = (HttpURLConnection) realUrl.openConnection();
            // 设置具体的方法,也就是具体的定时任务
            connection.setRequestMethod(method);
            // POST请求需要output
            connection.setDoOutput(isPostMethod);
            connection.setDoInput(true);
            connection.setUseCaches(false);
            connection.setReadTimeout(900 * 1000);
            connection.setConnectTimeout(600 * 1000);
            // connection:Keep-Alive 表示在一次http请求中,服务器进行响应后,不再直接断开TCP连接,而是将TCP连接维持一段时间。
            // 在这段时间内,如果同一客户端再次向服务端发起http请求,便可以复用此TCP连接,向服务端发起请求。
            connection.setRequestProperty("connection", "keep_alive");
            // Content-Type 表示客户端向服务端发送的数据的媒体类型(MIME类型)
            connection.setRequestProperty("content-type", "application/json;charset=UTF-8");
            // Accept-Charset 表示客户端希望服务端返回的数据的媒体类型(MIME类型)
            connection.setRequestProperty("Accept-Charset", "application/json;charset=UTF-8");
            // gateway请求转发到其他应用
            connection.connect();
            // 如果是POST请求,则判断定时任务是否含有执行参数
            if (isPostMethod && StringUtils.isNotBlank(data)) {
                DataOutputStream dataOutputStream = new DataOutputStream(connection.getOutputStream());
                // 写参数
                dataOutputStream.write(data.getBytes(Charset.defaultCharset()));
                dataOutputStream.flush();
                dataOutputStream.close();
            }
            int responseCode = connection.getResponseCode();
            // 判断请求转发、定时任务触发是否成功
            if (responseCode != 200) {
                throw new RuntimeException("Http Request StatusCode(" + responseCode + ") Invalid");
            }
            bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream(), Charset.defaultCharset()));
            StringBuilder stringBuilder = new StringBuilder();
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                stringBuilder.append(line);
            }
            String responseMsg = stringBuilder.toString();
            log.info("xxlJob调度执行返回数据={}", responseMsg);
            XxlJobHelper.log(responseMsg);
        } catch (Exception e) {
            XxlJobHelper.log(e);
            XxlJobHelper.handleFail();
        } finally {
            try {
                if (bufferedReader != null) {
                    bufferedReader.close();
                }
                if (connection != null) {
                    connection.disconnect();
                }
            } catch (Exception e) {
                XxlJobHelper.log(e);
            }
        }
    }
}

稍微有点麻烦的是,每个Spring Cloud应用都需要手动新增一个ScheduleController:

/**
 * 定时任务入口,所有服务的@RequestMapping满足/schedule/appName这种格式,方便统一管理
 **/
@RestController
@RequestMapping("/schedule/search")
public class ScheduleController {
    @Resource
    private ChineseEnglishStoreSchedule chineseEnglishStoreSchedule;

    @GetMapping("/chineseEnglishStoreSchedule")
    public Response<Boolean> chineseEnglishStoreSchedule() {
        chineseEnglishStoreSchedule.execute();
        return Response.success(true);
    }
}

另外,需要在gateway网关服务里新增路由转发规则:
Spring@Scheduled定时任务接入XXL-JOB的一种方案(基于SC Gateway),Spring Cloud,gateway
每个有定时任务,且准备接入XXL-JOB平台的SC微服务,都需要新增类似上面截图里的4条配置信息。

优点:所有带有定时任务的服务一目了然,方便统一维护和管理。

这种方案无需改造具体的某个Schedule类:

@JobHander(value = "autoJobHandler")
public class AutoJobHandler extends IJobHandler {
	@Override
    public ReturnT<String> execute(String... params) {
    try {
    	// 既有的业务逻辑
    	// 执行成功
    	return ReturnT.SUCCESS;
    } catch (Exception e) {
            logger.error("execute error id:{}, error info:{}", id, e);
            return ReturnT.FAIL;
        }
        return ReturnT.SUCCESS;
    }
}

最后都省却不了的一个步骤,在XXL-JOB admin管理平台新增一个个任务:
Spring@Scheduled定时任务接入XXL-JOB的一种方案(基于SC Gateway),Spring Cloud,gateway

验证

任务调度的执行日志:
Spring@Scheduled定时任务接入XXL-JOB的一种方案(基于SC Gateway),Spring Cloud,gateway
ELK日志查询平台里也可以搜索到逻辑代码里打印的日志。文章来源地址https://www.toymoban.com/news/detail-665597.html

参考

到了这里,关于Spring@Scheduled定时任务接入XXL-JOB的一种方案(基于SC Gateway)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【分布式任务调度平台 XXL-JOB 急速入门】从零开始将 XXL-JOB 接入到自己的项目

                                    💧 分布式任务调度平台 X X L − J O B 急速入门:从零开始将 X X L − J O B 接入到自己的项目 color{#FF1493}{分布式任务调度平台 XXL-JOB 急速入门:从零开始将 XXL-JOB 接入到自己的项目} 分布式任务调度平台 XX L − J OB 急速入门:从零

    2024年02月14日
    浏览(47)
  • XXL-JOB定时任务框架(Oracle定制版)

    xxl-job是一个轻量级、易扩展的分布式任务调度平台,能够快速开发和简单学习。开放源代码并被多家公司线上产品使用,开箱即用。尽管其确实非常好用,但我在工作中使用的是Oracle数据库,因为xxl-job是针对MySQL设计的,所以使用起来需要进行一些魔改。为了方便后人使用,

    2023年04月13日
    浏览(52)
  • 分布式定时任务-XXL-JOB-教程+实战

    1.定时任务认识 1.1.什么是定时任务 定时任务是按照指定时间周期运行任务。使用场景为在某个固定时间点执行,或者周期性的去执行某个任务,比如:每天晚上24点做数据汇总,定时发送短信等。 1.2.常见定时任务方案 While + Sleep : 通过循环加休眠的方式定时执行 Timer和Time

    2024年02月16日
    浏览(48)
  • SpringBoot 集成 xxl-job 实现定时任务管理

    XXL-Job是一个功能强大的分布式任务调度框架,集成了Spring Boot后能够发挥更大的优势。它提供了分布式任务调度、任务执行报告、任务调度中心、良好的扩展性、分布式集群部署、监控与报警等多种优势。此外,XXL-Job是开源免费的,可以在GitHub上获取源代码和详细文档。详细

    2024年02月09日
    浏览(39)
  • springcloud:快速上手定时任务框架xxl-job(十五)

    实际开发中,我们常常遇到需要定时执行的任务,我们可以利用定时线程池或schedule框架等来实现定时任务,但这些方式都有效率、性能上的缺陷,在微服务框架下,我们期望一种更加规整、轻量、可靠的定时任务框架来帮助我们实现定时任务,以及可视化的管理定时任务。

    2023年04月08日
    浏览(47)
  • 第三代开源定时任务框架PowerJob-比xxl-job 更强大!

    这倒是勾起了我的好奇心,因为前段时间用  xxl-job 替换掉了同样不太好用的 QuartZ ,那时候还没有调研 PowerJob。于是这次研究了一番, 发现 PowerJob 确实是个很棒的框架 ,在这里推荐给大家。 PowerJob是新一代分布式任务调度与计算框架,支持CRON、API、固定频率、固定延迟等

    2023年04月10日
    浏览(38)
  • 【手把手】分布式定时任务调度解析之xxl-job

    在之前我写的讲解Quartz中有介绍过,Quartz有差不多二十年的历史,调度模型已经非常成熟了,而且很容易集成到Spring中去,用来执行业务任务是一个很好的选择。但是越早的设计存在的问题也越明显,比如: 1、调度逻辑(Scheduler)和任务类耦合在同一个项目中,随着调度任

    2024年01月19日
    浏览(64)
  • 分布式定时任务系列8:XXL-job源码分析之远程调用

    分布式定时任务系列1:XXL-job安装 分布式定时任务系列2:XXL-job使用 分布式定时任务系列3:任务执行引擎设计 分布式定时任务系列4:任务执行引擎设计续 分布式定时任务系列5:XXL-job中blockingQueue的应用 分布式定时任务系列6:XXL-job触发日志过大引发的CPU告警 分布式定时任

    2024年01月21日
    浏览(51)
  • spring boot + xxl-job 分布式任务调度

    1、任务调度 1.1、什么是任务调度 我们可以先思考一下下面业务场景的解决方案: 某电商系统需要在每天上午10点,下午3点,晚上8点发放一批优惠券。 某财务系统需要在每天上午10点前结算前一天的账单数据,统计汇总。 某电商平台每天凌晨3点,要对订单中的无效订单进行

    2024年02月09日
    浏览(63)
  • xxl-job定时任务配置应用以及添加到自己已有的springboot项目中实现动态API调用

    XXL-JOB是一个分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。 本篇文章主要是对xuxueli的xxl-job做一个简单的配置,以及将其添加到自己已有的项目中进行api调用。 一、xxl-job安装 1、首先

    2024年02月03日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包