一套万能通用的异步处理方案

往期热门文章:

1、微服务全做错了!谷歌提出新方法,成本直接降9倍!2、IntelliJ IDEA 2024 首个大版本发布,好用到爆!3、Web 后端的一生之敌:分页器4、ObjectMapper,别再像个二货一样一直new了!5、表设计的18条军规,你违反了几条?5、还在用Xshell?你out了,推荐一个更现代的终端连接工具

1 前言





良好的系统设计必须要做到开闭原则,随着业务的不断迭代更新,核心代码也会被不断改动,出错的概率也会大大增加。但是大部分增加的功能都是在扩展原有的功能,既要保证性能又要保证质量,我们往往都会使用异步线程池来处理,然而却增加了很多不确定性因素。由此我设计了一套通用的异步处理SDK,可以很轻松的实现各种异步处理文章来源:https://juejin.cn/post/7266087843239084090






2 目的





通过异步处理不仅能够保证方法能够得到有效的执行而且不影响主流程更重要的是各种兜底方法保证数据不丢失,从而达到最终一致性


3 优点





无侵入设计,独立数据库,独立定时任务,独立消息队列,独立人工执行界面(统一登录认证)使用spring事务事件机制,即使异步策略解析失败也不会影响业务如果你的方法正在运行事务,会等事务提交后或回滚后再处理事件就算事务提交了,异步策略解析失败了,我们还有兜底方案执行(除非数据库有问题,消息队列有问题,方法有bug)


4 原理





容器初始化bean完成后遍历所有方法,把有@AsyncExec注解的方法缓存起来方法运行时通过AOP切面发布事件事务事件监听处理异步执行策略
@TransactionalEventListener(fallbackExecution = true, phase = TransactionPhase.AFTER_COMPLETION)
  • fallbackExecution=true 没有事务正在运行,依然处理事件
  • TransactionPhase.AFTER_COMPLETION 事务提交后和事务回滚后都处理事件


5 组件





  • kafka 消息队列
  • xxl job 定时任务
  • mysql 数据库
  • spring 切面
  • vue 界面


6 设计模式





  • 策略
  • 模板方法
  • 动态代理


7 流程图







8 数据库脚本





CREATE TABLE `async_req` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `application_name` varchar(100) NOT NULL DEFAULT '' COMMENT '应用名称',
  `sign` varchar(50) NOT NULL DEFAULT '' COMMENT '方法签名',
  `class_name` varchar(200) NOT NULL DEFAULT '' COMMENT '全路径类名称',
  `method_name` varchar(100) NOT NULL DEFAULT '' COMMENT '方法名称',
  `async_type` varchar(50) NOT NULL DEFAULT '' COMMENT '异步策略类型',
  `exec_status` tinyint NOT NULL DEFAULT '0' COMMENT '执行状态 0:初始化 1:执行失败 2:执行成功',
  `exec_count` int NOT NULL DEFAULT '0' COMMENT '执行次数',
  `param_json` longtext COMMENT '请求参数',
  `remark` varchar(200) NOT NULL DEFAULT '' COMMENT '业务描述',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `idx_applocation_name` (`application_name`) USING BTREE,
  KEY `idx_exec_status` (`exec_status`) USING BTREE
) ENGINE
=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='异步处理请求';

CREATE TABLE `async_log` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `async_id` bigint NOT NULL DEFAULT '0' COMMENT '异步请求ID',
  `error_data` longtext COMMENT '执行错误信息',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `idx_async_id` (`async_id`) USING BTREE
) ENGINE
=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='异步处理日志';


9 异步策略







10 安全级别







11 执行状态







12 流程图







13 apollo 配置





# 开关:默认关闭
async.enabled=true

# 应用名称
spring.application.name=xxx

# 数据源 druid 
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/fc_async?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowMultiQueries=true&rewriteBatchedStatements=true
spring.datasource.username=user
spring.datasource.password=xxxx
spring.datasource.filters=config
spring.datasource.connectionProperties=config.decrypt=true;config.decrypt.key=yyy
#静态地址
spring.resources.add-mappings=true
spring.resources.static-locations=classpath:/static/


# 以下配置都有默认值
# 核心线程数
async.executor.thread.corePoolSize=10
# 最大线程数
async.executor.thread.maxPoolSize=50
# 队列容量
async.executor.thread.queueCapacity=10000
# 活跃时间
async.executor.thread.keepAliveSeconds=600

# 执行成功是否删除记录:默认删除
async.exec.deleted=true
 
# 自定义队列名称前缀:默认应用名称
async.topic=${spring.application.name}
 
# 重试执行次数:默认5
async.exec.count=5
 
# 重试最大查询数量
async.retry.limit=100

# 补偿最大查询数量
async.comp.limit=100

# 登录拦截:默认false
async.login=false



14 用法





1,异步开关
scm.async.enabled=true
2,在需要异步执行的方法加注解 (必须是spring代理方法)
@AsyncExec(type = AsyncExecEnum.SAVE_ASYNC, remark = "数据字典")
3,人工处理地址
http://localhost:8004/async/index.html



15 注意





1,应用名称
spring.application.name
2,队列名称
${async.topic:${spring.application.name}}_async_queue
自定义topic:async.topic=xxx3,自己业务要做幂等4,一个应用公用一个队列自产自消5,定时任务
  • 异步重试定时任务(2分钟重试一次,可配置重试次数)
  • 异步补偿定时任务(一小时补偿一次,创建时间在一小时之前的)



16 效果展示







17 github地址





https://github.com/xiongyanokok/fc-async.git
往期热门文章:

1为什么现在Java连Date类都不建议使用了?2、Java 极限操作3、100万级安装量的开源作品,一年有多少打赏收入?4、编写 if 时尽量不要带 else?5、Redis只能做缓存?太out了!6、目前工资最高的几家外包公司汇总!(2024最新版)7、工作中最常见的6种OOM问题8、千万不要滥用Stream.toList(),有坑!9、强烈建议你不要再使用Date类了!!!10、IDEA 接口调试神器,贼好用!

相关推荐

  • 关于虚拟DOM(面试必看)
  • 面试官:如何判断两个数组的内容是否相等
  • 融合ChatGPT+DALL·E 3,贾佳亚团队新作开源畅玩:识图推理生图一站解决
  • 扩散模型的原理及实现(Pytorch)
  • “小同学”如何在大公司里快速落地?
  • 40岁,阿里P9,狗日的2023年
  • Vue3 超前版发布三个新特性!有望全面拥抱 JSX/TSX!
  • AI音乐,8大变现方式——Suno:音乐版的ChatGPT - 第505篇
  • 五年沉淀,微信全平台终端数据库WCDB迎来重大升级!
  • 这个ChatGPT4.0,真好用!
  • 一周涨 15k Star 的开源项目「GitHub 热点速览」
  • 面试官:为什么HashMap 使用的时候指定容量?
  • 面试官:你说说 Mysql 索引失效有哪些场景?
  • 上海一对夫妻自爆现状:老公失业被裁,老婆宁愿净身出户也要离婚,房贷欠100多万,存款接近0,这日子怎么过下去......
  • 21 世纪的工作方法论:工作八正道
  • 分享几款超好用的JVM调优工具,建议收藏!
  • OpenAI CEO Sam Altman 和COO Brad 最新精彩联合访谈 · 完整版+视频
  • [开源]一个开源的多端即时聊天工具,快速建立企业内部通讯系统
  • 斩获WSDM 2024冠军方案!
  • 图解 ElasticSearch 搜索原理