首页 星云 工具 资源 星选 资讯 热门工具
:

PDF转图片 完全免费 小红书视频下载 无水印 抖音视频下载 无水印 数字星空

集群及分布式定时任务中间件MEE_TIMED

编程知识
2024年07月19日 22:08

集群及分布式定时任务中间件MEE_TIMED

转载请著名出处:https://www.cnblogs.com/funnyzpc/p/18312521

MEE_TIMED一套开源的定时任务中间件,MEE_TIMED 简化了 scheduledshedlock的配置,同时也升级了这两种中间件的能力 ,使定时任务开发更具灵活性的同时
具备集群及分布式节点的管理,同时也增加了传参,使之更加强大💪

开发初衷

    目前 java 语言下可用的定时任务基础组件无非这俩: spring scheduled 以及 quartz,其中 scheduled 属于轻量级的设计 默认集成在 spring-context 包中,所以springboot使用 scheduled 简单快捷,
既然简单也必有简单的局限(后面会聊),quartz 则属于重量级的设计,内部提供了 RMIJMX 支持 以及使用基于DB的行锁使之支持集群,这都很好,不过内部代码设计及扩展似乎过于臃肿,不使用表又会退化为 scheduled ~

    有时,项目不大不小,但是有集群需求并且需要保证任务不重复执行,这时就需要 scheduled+shedlock 这样的搭配,可这样无法动态传参,同时增加了业务代码的复杂度,这是问题;
当然也可以使用 quartz+数据库表 的方式 则管理集群及节点任务会变得比较复杂, 而且任务的启停及关闭操作在分布式环境下使用 quartz 提供的api操作尤其的麻烦,这也是问题...

  • spring scheduled 所面临的问题:

    • CRON表达式过于简单,不支持复杂的表达式,比如每月最后一天,虽然提供zone支持但在特殊的国度,如在美国,无法计算夏令时及冬令时的偏差
    • @Schedules@SchedulerLock配合时 多执行时间 会存在被锁定的问题
    • scheduled 如果不指定线程池时 默认是单线程执行,不管应用下有多少定时任务都会是单线程,这是瓶颈...
    • scheduled 不支持传参,函数使用时必须是void的函数返回且不可有形参
    • 部分api可能存在spring版本迭代时不兼容问题,这是二开可能的问题
  • shedlock 的不足之处:

    • 无法做集群及分布式节点管理,除非key定义的十分小心
    • 不太好通过锁的控制做任务及节点的启停控制(可以通过特殊方法 比较另类)
    • 任务执行时的关键信息默认不记录(IP、时间、CRON、应用信息等等)
    • 加锁过程可能存在不必要的更新操作(这是代码问题)

基于现有情况我改造了 scheduled,用较少的更改 做出了处于 scheduledquartz 中间的定时任务组件,这就是 MEE_TIMED 🌹.

MEE_TIMED 所做的改进

  • 新增app表(SYS_SHEDLOCK_APP),提供集群及多节点控制支持
  • 扩展job(SYS_SHEDLOCK_JOB)表data字段,提供传参及参数修改支持
  • @Schedule@SchedulerLock 二合一并简化注解配置
  • spring scheduledCronExpression 替换为 quartzCronExpression,支持更灵活更复杂的CRON表达式
  • 修改掉 scheduled 内部默认单线程的问题,提供线程池支持
  • 固定于spring强绑定的api,尽量与springboot兼容性做到最佳
  • 任务信息落表 等等

基本使用

详细配置代码及后台集成在mee-admin有实例 👊(,)👊

  • 1.下载 表结构 及 mee_timed-X.X.X.jar 依赖 依赖 并存放于项目或nexus私服中

  • 2.POM中定义dependency依赖:

            <dependency>
                <groupId>com.mee.timed</groupId>
                <artifactId>mee_timed</artifactId>
                <version>1.0.1</version>
                <scope>system</scope>
                <systemPath>${pom.basedir}/src/main/resources/lib/mee_timed-1.0.1.jar</systemPath>
            </dependency>
    
  • 3.导入表结构(SQL)

    根据所使用的db,按需导入对应厂商所支持的表结构,目前仅提供 mysqloraclepostgresql支持:

        table_mysql.sql
        table_oracle.sql
        table_postgresql.sql
    
  • 4.定义配置及bean

    目前配置仅有三项:

    spring.mee.timed.shed=${spring.application.name}
    spring.mee.timed.table-name=SYS_SHEDLOCK_JOB
    spring.mee.timed.table-app-name=SYS_SHEDLOCK_APP
    

    其中配置项spring.mee.timed.table-app-name是管理集群及节点用的,如不需要可不配置
    应用启动时会自动写入必要的初始化参数,也可提前将初始数据提前导入

    配置bean: 这一步是非必须的,只是内部线程池的配置较为保守,如需自定义可以以下配置指定线程数及线程名前缀:

        /**
         * 设置执行线程数
         * @return
         */
        @Bean
        public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
            ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
            scheduler.setPoolSize(PROCESSOR*2);
            scheduler.setThreadNamePrefix("SHEDLOCK-");
            scheduler.initialize();
            return scheduler;
        }
    
  • 5.定义定时任务

    样例一:

    
    import com.mee.timed.Job;
    import com.mee.timed.JobExecutionContext;
    import com.mee.timed.annotation.MeeTimed;
    import com.mee.timed.annotation.MeeTimeds;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    
    import java.util.concurrent.TimeUnit;
    
    @Component
    public class Job01TestService implements Job {
        private static final Logger LOGGER = LoggerFactory.getLogger(Job01TestService.class);
    
        @MeeTimed(fixedRate = 10000,lockAtLeastFor = "PT5S",lockAtMostFor ="PT5S" )
        public void exec01() throws InterruptedException {
            LOGGER.info("=====> [exec01] Already Executed! <=====");
            TimeUnit.SECONDS.sleep(6);
        }
    
        @MeeTimeds({
             @MeeTimed(cron = "10,20,30,40,50 * * * * ?",lockAtMostFor ="PT5S",lockName = "execute1"),
             @MeeTimed(cron = "0 0/2 * * * ?",lockAtMostFor ="PT1M",lockName = "execute2"),
             @MeeTimed(cron = "0 0/4 * ? * MON-FRI",lockAtMostFor ="PT1M",lockName = "execute3"),
             // 纽约时间每年的7月9号22点2分执行
             @MeeTimed(cron = "0 2 22 9 7 ?",lockAtMostFor ="PT1M",lockName = "execute4",zone = "America/New_York"),
             // 每月最后一天的十点半(eg:2024-07-31 10:30:00)
             @MeeTimed(cron = "0 30 10 L * ?",lockAtMostFor ="PT1M",lockName = "execute5")
        })
        @Override
        public void execute(JobExecutionContext context)   {
            LOGGER.info("=====> proxy job exec! data:"+context.getJobInfo().getName()+"  <=====");
            try {
                TimeUnit.SECONDS.sleep(8);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    
    }
    

    样例二:

    package com.mee.timed.test.job;
    
    import com.mee.timed.annotation.MeeTimed;
    import com.mee.timed.annotation.MeeTimeds;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    
    @Component
    public class ScheduledTasks {
        private static final Logger LOGGER = LoggerFactory.getLogger(ScheduledTasks.class);
    
        @MeeTimeds({
                @MeeTimed(fixedRate = 10000,lockAtLeastFor = "PT5S",lockAtMostFor ="PT5S",lockName = "T1"),
                @MeeTimed(fixedDelay = 8000,lockAtLeastFor = "PT5S",lockAtMostFor ="PT5S",lockName = "T2"),
        })
        public void exec01() {
            LOGGER.info("=====> [exec01] Already Executed! <=====");
        }
    
        @MeeTimed(cron = "0/20 * * * * ?",lockAtLeastFor = "PT5S",lockAtMostFor ="PT10S" )
        public void exec02(JobExecutionContext context) {
            LOGGER.info("=====> proxy job exec! data:"+context.getJobDataJson()+"  <=====");
        }
        
    }
    

    以上两种方式均可,如果需要传递参数 其函数的形参数 必须是 JobExecutionContext 或其实现类

    如果是同一函数多时间配置(使用 @MeeTimeds 配置),其每一项 lockName 不可为空!

集成后台管理

  • 具体效果及代码集成 具体见: mee-admin

  • 后台配置及管理

实际执行效果

2024-07-18 09:59:20.006 -> [MEE_TIMED-7] -> INFO  com.mee.cron.JobTimedService:25 - =====> proxy job exec! data:{"key":"执行数据"}  <=====
2024-07-18 09:59:40.020 -> [MEE_TIMED-7] -> INFO  com.mee.cron.JobTimedService:25 - =====> proxy job exec! data:{"key":"执行数据"}  <=====
2024-07-18 09:59:59.993 -> [MEE_TIMED-1] -> INFO  com.mee.cron.DefaultTimerService:27 - ===>testTask2執行時間: 2024-07-18 09:59:59
2024-07-18 10:00:00.003 -> [MEE_TIMED-5] -> INFO  com.mee.cron.DefaultTimerService:21 - ===>testTask1執行時間: 2024-07-18 10:00:00
2024-07-18 10:00:00.009 -> [MEE_TIMED-4] -> INFO  com.mee.cron.JobTimedService:25 - =====> proxy job exec! data:{"key":"执行数据"}  <=====
2024-07-18 10:00:20.014 -> [MEE_TIMED-4] -> INFO  com.mee.cron.JobTimedService:25 - =====> proxy job exec! data:{"key":"执行数据"}  <=====
2024-07-18 10:00:40.015 -> [MEE_TIMED-4] -> INFO  com.mee.cron.JobTimedService:25 - =====> proxy job exec! data:{"key":"执行数据"}  <=====
2024-07-18 10:01:00.019 -> [MEE_TIMED-4] -> INFO  com.mee.cron.JobTimedService:25 - =====> proxy job exec! data:{"key":"执行数据"}  <=====

后续计划

  1. 首先是传参考虑做反序列化处理,在必要场景下这是需要的

  2. fix bug,当然这需要码友多多支持啦

  3. 动态修改执行时间,尤其是cron,这功能是与quartz的差距的缩小是决定性的

  4. 执行日志支持,并提供扩展支持

  5. 其他待定

最后

再次感谢 spring scheduledshedlock 的开源,MEE_TIMEDgithub 有开源,详见: https://github.com/funnyzpc/mee_timed_parent 🎈

From:https://www.cnblogs.com/funnyzpc/p/18312521
本文地址: http://shuzixingkong.net/article/209
0评论
提交 加载更多评论
其他文章 C#/.NET这些实用的编程技巧你都会了吗?
DotNet Exercises介绍 DotNetGuide专栏C#/.NET/.NET Core编程常用语法、算法、技巧、中间件、类库练习集,配套详细的文章教程讲解,助你快速掌握C#/.NET/.NET Core各种编程常用语法、算法、技巧、中间件、类库等等。 GitHub开源地址:https:/
C#/.NET这些实用的编程技巧你都会了吗?
阅读翻译Prompting Engineering Guides之Introduction(提示工程简介)
阅读翻译Prompting Engineering Guides之Introduction(提示工程简介) 关于 首次发表日期:2024-07-19 Prompting Engineering Guides官网: https://www.promptingguide.ai/zh 使用ChatGPT和
阅读翻译Prompting Engineering Guides之Introduction(提示工程简介)
CF466E Information Graph 题解
题目链接 Luogu Codeforces 题意简述 某公司中有 \(n\) 名员工。为方便起见,将这些员工从 1 至 \(n\) 编号。起初,员工之间相互独立。接下来,会有以下 \(m\) 次操作: 员工 \(y\) 成为员工 \(x\) 的上司。保证此前 \(x\) 没有上司。 员工 \(x\)
即将被淘汰 这几门编程语言!
又到了周五了,忙碌了一周,可以放松放松一下了! 在科技迅速发展的今天,编程语言的更新迭代速度令人惊叹。从经典的C语言到现代的Python, 编程语言不断进化,满足着不同领域的需求。然而,有些编程语言却逐渐淡出我们的视野。 你是否好奇,哪些编程语言即将被淘汰? 哪些编程语言正面临被淘汰的危机?它们的逐
即将被淘汰 这几门编程语言! 即将被淘汰 这几门编程语言! 即将被淘汰 这几门编程语言!
构建基于Java Spring Boot和Uniapp的心理小程序:从零到一的完整指南
构建基于Java Spring Boot和Uniapp的心理小程序:从零到一的完整指南 前言 大家好,今天我们来聊聊如何使用Java Spring Boot和Uniapp构建一个心理小程序。这个项目不仅能帮助你提升技术水平,还能为用户提供心理健康支持。我们将从项目的整体架构开始,逐步深入到具体的代码
wails实现腾讯元器bot
简单记录工具的一个模块 后端 Api调用 登录 腾讯元器 后创建智能体,按自己的需求来创建,发布后要等等审核。 ​​ 等发布完成后点击调用api即可,这里可以看到user_id​, assistant_id​,token​参数 ​​ 使用github.com/chenmingyong0423/go-
wails实现腾讯元器bot wails实现腾讯元器bot wails实现腾讯元器bot
GitHub Star 数量前 12 的开源无代码工具
相关文章:GitHub Star 数量前 15 的开源低代码项目 在本篇文章中,我们将探索 12 款在 GitHub 上星级排名前列的开源无代码工具。 每款工具都旨在简化和加速开发过程,但各自侧重于不同的应用场景。 从动态表单生成的 Formily,到高度可定制的 NocoBase 用于复杂业务系统
GitHub Star 数量前 12 的开源无代码工具 GitHub Star 数量前 12 的开源无代码工具 GitHub Star 数量前 12 的开源无代码工具
Langchain 与 LlamaIndex:LLM 应用开发框架的比较与使用建议
Langchain 和 Llamaindex 是两种广泛使用的主流 LLM 应用开发框架。两者有什么不同?我们该如何使用?以下我根据各类资料和相关文档做了初步选型。 一、Langchain 1. 适用场景 (1)需要构建灵活、可扩展的通用应用程序。 (2)需要复杂的工作流程支持。 (3)需要复杂的交