高性能异步任务编排框架:Gobrs-Async
前言
在实际业务开发中为了让程序性能更高通常我们会采用多线程编程,或者采用CompletableFuture进行异步编排,它提供了基础的多任务处理能力,适用于粒度较细、依赖关系简单的异步编程,但在复杂业务场景下仍显力不从心,代码会特别臃肿不便维护。
为了解决这一问题,我们公司采用了 Gobrs-Async 异步编排框架通过声明式配置来取代CompletableFuture的命令式编码。它封装了复杂异步编排的细节,提供了更高阶、更强大的功能,专门为解决中大型项目中复杂的、可配置的、需要严密监控的异步任务流程而设计,使用 Gobrs-Async 会极大地提升开发效率和系统稳定性
认识Gobrs
Gobrs-Async 看作是由 dromara 开源社区 孵化和支持的项目,dromara 是一个致力于开源协作的组织,孵化了多个优秀的国产开源项目,如 Hutool、SaToken、EasyES、LiteFlow 等。
Gobrs-Async (opens new window)是一款功能强大、配置灵活、带有全链路异常回调、内存优化、异常状态管理于一身的高性能多线程并发编程和动态编排框架。为企业提供在复杂应用场景下动态任务编排的能力。 针对于复杂场景下,异步线程复杂性、任务依赖性、异常状态难控制性; Gobrs-Async 为此而生。
与传统解决方案如 CompletableFuture 相比,Gobrs-Async 提供了更全面的任务管理能力。它不仅支持任务结果的传递,还实现了对每个执行单元的完整回调机制。这意味着开发者可以在任务执行成功后记录日志,或在失败时记录异常信息,实现了对异步流程的精细监控
Gobrs-Async 在电商平台等高性能要求的环境中经历了严格考验,能够有效提升系统整体QPS,是现代Java开发者处理异步任务依赖和编排的强力工具。
通过简洁的配置和强大的API,Gobrs-Async 让开发者能够从繁琐的多线程管理工作中解脱出来,更加专注于业务逻辑的实现
官网:https://async.sizegang.cn/ ; 源码:https://github.com/dromara/gobrs-async
Gobrs-Async的核心特性包括:
- 基于Spring Boot:集成Spring Boot的自动配置,使得集成到现有Spring生态系统中变得简单快捷
- 多线程模型:支持多线程并行处理任务,充分利用硬件资源,提高系统吞吐量。 任务队列:使用内部的任务队列,保证任务的顺序执行或者批量处理。
- 任务回调:提供丰富的回调机制,允许开发者在任务开始、结束或异常时进行操作。
- 健康检查与监控:内建健康检查接口,便于集成如Prometheus等监控工具,实时了解任务状态。
- 故障重试与超时控制:对失败的任务进行重试,且可以设定超时策略,确保系统的健壮性。
Gobrs-Async适用于各种需要异步处理的场景,例如:
- 后台数据计算:如大数据处理、报表生成等,避免阻塞主线程影响用户体验。
- 消息通知:发送邮件、短信通知等,异步处理避免响应延迟。
- 高并发请求:处理大量短生命周期的请求,提高系统处理能力。
- 定时任务:定期执行的日志清理、缓存更新等操作。
Gobrs-Async特点优势:
- 简洁的API:易于理解和使用的API设计,降低学习成本。
- 高度可定制:可以根据实际需求调整任务处理策略,满足个性化需求。
- 稳定性保障:经过严格测试,确保在复杂环境下稳定运行。
- 社区支持:作为Dromara家族的一员,享有活跃的社区和及时的技术支持。
使用Gobrs=
1.环境准备
- JDK:17
- SpringBoot:2.5.8
导入SpringBoot基础依赖和Gobrs基础依赖
<properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.5.8</version></parent><dependencies><dependency><groupId>io.github.memorydoc</groupId><artifactId>gobrs-async-starter</artifactId><version>1.3.0-RELEASE</version></dependency></dependencies>
接着完成启动类的编写。
2.Gobrs入门
2.1.创建任务Service
下面我们使用三个Service来演示Gobrs的异步编排功能:HelloAService、HelloBService、HelloCService。三个service都继承AsyncTask
,如下
- AsyncTask<入参类型,结果类型> :异步任务基类,提供了入参,和出参的泛型
- 创建 Bean 继承 AsyncTask
- 标记 @Task 注解
@Slf4j
@Task
public class HelloAService extends AsyncTask<HelloContent, HelloContent> {@Overridepublic HelloContent task(HelloContent helloParam, TaskSupport taskSupport) {log.info("拿到初始参数 param = {} ",taskSupport.getParam());return new HelloContent().appendServiceName("HelloAService");}@Overridepublic void prepare(HelloContent helloContent) {log.info("prepare 执行 ... ");}@Overridepublic void onSuccess(TaskSupport support) {log.info("onSuccess 执行 ... ");}@Overridepublic void onFail(TaskSupport support, Exception exception) {log.info("onFail 执行 ... ");super.onFail(support, exception);}@Overridepublic boolean nessary(String params, TaskSupport support) {// 假如参数是cancel 则不执行当前任务if("cancel".equals(params)){return false;}return true;}}
- task : 任务方法,方法提供了TaskSupport 对象,该对象种封装了任务名、参数、任务结果等。
- prepare :task方法执行前执行
- onSuccess :执行成功了执行,如果你想在任务执行完成后做一些额外的操作。例如打印日志、发送邮件、发送MQ、记录信息等。 Gobrs-Async 同样也为你考虑到了。通过实现 callback 方法。会让你轻松的拿到 任务的执行结果。
- onFail :失败了执行
- nessary :Gobrs-Async 会根据 nessary 的返回结果,判断当前task 是否需要执行 如果返回true 则需要被执行,否则反之。
HelloBService 和 HelloCService 同上 , 下面是自定义的上下文对象,用于service之间传参,这里搞了一个StringBuilder来组装数据
/*** 参数** @author chengang1* @date 2025-07-18*/
@Accessors(chain = true)
@Data
public class HelloContent {private StringBuilder stringBuilder = new StringBuilder();public HelloContent appendServiceName(String serviceName){this.stringBuilder.append(serviceName).append("->");return this;}
}
2.2.配置规则
gobrs:async:config:rules:# 规则 是数组类型的 多组规则- name: "helloRule"content: "HelloAService->HelloBService->HelloCService" # 三个服务串行task-interrupt: false # 局部异常是否打断主流程 默认falseinterruptionImmediate: false #立即中断catchable: false #异常抛出到main线程transaction: false #支持回滚logConfig:costLogabled: true # 开启任务耗时打印 log日志级别需要为 error 默认trueerrLogabled: true # 开启任务异常打印 默认true
- name: “helloRule” : 规则名
- content: “HelloAService->HelloBService->HelloCService” # 服务编排:三个服务串行
2.3.编写测试
编写SpringBoot测试类 ,注入:GobrsAsync ,通过调用go方法执行规则
@SpringBootTest(classes = GobrsAsyncApplication.class)
@Slf4j
class HelloAServiceTest {@Autowiredprivate GobrsAsync gobrsAsync;@Testpublic void test(){HashMap<String, String> param = new HashMap<>();param.put("init","1");AsyncResult helloRule = gobrsAsync.go("helloRule", () -> param);log.info("result = {}",helloRule.getResultMap());}
执行效果:
现在我们新建一个规则:helloAsyn,让HelloAService,HelloBService并行执行,最后执行HelloCService
gobrs:async:config:rules:# 规则 是数组类型的 多组规则- name: "helloRule"content: "HelloAService->HelloBService->HelloCService" # 三个服务串行task-interrupt: false # 局部异常是否打断主流程 默认falseinterruptionImmediate: false #立即中断catchable: false #异常抛出到main线程transaction: false #支持回滚logConfig:costLogabled: true # 开启任务耗时打印 log日志级别需要为 error 默认trueerrLogabled: true # 开启任务异常打印 默认true- name: "helloAsyn"content: "HelloAService,HelloBService->HelloCService" # HelloAService和HelloBService并行执行完成后,再执行HelloCServicetask-interrupt: false # 局部异常是否打断主流程 默认falseinterruptionImmediate: false #立即中断catchable: false #异常抛出到main线程transaction: false #支持回滚logConfig:costLogabled: true # 开启任务耗时打印 log日志级别需要为 error 默认trueerrLogabled: true # 开启任务异常打印 默认true
执行效果:
更多的编排规则可以参考官网:https://async.sizegang.cn/pages/2ffsdnaa/#%E5%9C%BA%E6%99%AF%E4%B8%80
3.重试任务
执行中的任务会出现异常的情况,如果使用者有对任务失败重试的需求,Gobrs-Async 也为你提供了支持,只需要在 需要开启重试的任务 bean 中使用 @Task(retryCount = 10) 注解,框架则自动会为你开启重试模式。 retryCount 所跟的数字为 重试次数
@Component
@Task(retryCount = 10)
public class HelloAService extends AsyncTask<Object, Object> {
// ...
}
4.事务任务
使用者可能有这种事务需求的业务,比如 A -> B -> C 的场景,如果C执行失败了, 则通知 A和B 任务进行业务回滚。 则这种方式 Gobrs-Async 也是支持的 事务任务也需要继承 AsyncTask, 唯一的区别就是以下三个步骤。
- 第一步开启事务支持:transaction: true #支持回滚
gobrs:async:config:rules:# 规则 是数组类型的 多组规则- name: "helloRule"content: "HelloAService->HelloBService->HelloCService" # 三个服务串行task-interrupt: false # 局部异常是否打断主流程 默认falseinterruptionImmediate: false #立即中断catchable: false #异常抛出到main线程transaction: true #支持回滚logConfig:costLogabled: true # 开启任务耗时打印 log日志级别需要为 error 默认trueerrLogabled: true # 开启任务异常打印 默认true
在你需要进行事务的任务上进行回滚注解, Gobrs-Async 会找到 helloRule任务链之前的所有任务 回调rollback 方法
- @Task(callback = true) : 开启回调、复写 rollback 实现回滚逻辑
@Slf4j
@Task(callback = true)
public class HelloAService extends AsyncTask<HelloContent, HelloContent> {@Overridepublic void rollback(HelloContent helloContent) {//事务回滚逻辑...super.rollback(helloContent);}
5.超时任务
何为超时任务? 顾名思义其实就是单一任务可以通过设置超时时间决定任务是否继续执行。配置方式很简单。如下操作:
注解配置 使用 @Task注解中的 timeoutInMilliseconds 属性进行配置。
- timeoutInMilliseconds 固定使用毫秒数
@Task(timeoutInMilliseconds = 300)
public class CaseTimeoutTaskA extends AsyncTask {
- 开启超时监听线程数量:
gobrs:async:config:rules:- name: "chain1"content: "taskA->taskB->taskC"timeout-core-size: 200 # 核心线程数量
6.方法任务
相信看到这里的小伙伴大概已经了解Gobrs-Async如何创建一个普通任务(创建一个类继承自AsyncTask),那么有的小伙伴觉的业务不是很复杂,只是单纯的多线程开发,不想 开启一个任务就创建一个类。这违背了多线程简单上手的初衷。 那么这种场景下如何快速完成多线程开发,并且具备管理多线程(重试、回调、监控、超时)的能力呢? - 开启方法任务
开启方法任务很简单(默认不开启方法任务,完全按照小伙伴开发喜好设计),只需要在SpringBoot启动类中编写 @EnabledMethodTask 注解即可开启方法任务
@EnabledMethodTask
@SpringBootApplication
public class GobrsAsyncTestApplication {/*** The entry point of application.* @param args the input arguments*/public static void main(String[] args) {SpringApplication.run(GobrsAsyncTestApplication.class, args);}
}
声明方法任务组件
-
只需要在需要想要开启方法任务的业务 service 中编码 @MethodComponent注解,则标识该类为 Gobrs-Async的方法任务组件。@MethodComponent 注解默认集成Spring的 @Component注解,无须重复引入。
-
需要使用 @MethodTask 注解到所要开启任务的方法上即可, 同时注解了@MethodTask的方法也兼容直接当作普通方法调用,也就是说对参数没有任何限制。
配置案例如下
@MethodComponent 标识类为方法任务组件, 注解在类上。@MethodTask 方法任务标识, 注解在方法上 。参数如下:
- name: 方法任务名称需与 Gobrs-Async 配置文件中的 task 名称匹配,如果不编写。则默认取该注解方法的名称(会判重)
- invoke: 配置方法任务的 回调方法(成功、失败、回滚、必要条件)与 @Task注解中的配置项匹配
- config: 配置方法任务的任务属性(超时时间、重试次数、描述、是否具备事务属性、异常是否继续执行、描述)
@MethodComponent
public class CaseMethodTaskOne {@MethodTask(name = "normal")public String normal(TaskSupport taskSupport) throws InterruptedException {String context1 = taskSupport.getParam("normal", String.class);Thread.sleep(1000);Assertions.assertThat(context1).isEqualTo("context");return TASK_1_RESULT;}/*** Normal 2 string.** @return the string*/@SneakyThrows@MethodTaskpublic String normal2(String param1, String param2, TaskSupport support) {Assertions.assertThat(param1).isEqualTo("context");/*** 获取 task1 的返回结果*/String task1Result = support.getResult("normal", String.class);Assertions.assertThat(task1Result).isEqualTo(TASK_1_RESULT);Thread.sleep(1000);return "task2";}
yml任务编排配置
gobrs:async:config:rules:- name: "launcher"content: "normal->normal2"
参考:https://async.sizegang.cn/pages/2fsdl4fmn/#%E5%AE%8C%E6%95%B4%E6%A1%88%E4%BE%8B
总结
本文介绍了Gobrs-Async框架相比传统线程池方案或者CompletableFuture方案的优势,并在SpringBoot环境中对Gobrs进行了编码实战,以及介绍了Gobrs的多种任务如:重试任务,超时任务等,虽然Gobrs很强大,但是在小规模项目使用传统线程池或CompletableFuture就能满足需求就没必要使用Gobrs了。