Giter VIP home page Giter VIP logo

turbo's Introduction

Turbo 简介

Turbo是一款Java实现的轻量级流程引擎,是公司内多个低代码平台的核心后端服务。

特性

  1. 提供“定义流程,并根据流程定义,执行流程”的核心能力

  2. 轻量级的库表操作

  3. 支持流程回滚操作

核心能力

我们提供了以下核心能力:

  1. 流程定义:保存流程基本信息和流程图模型

  2. 流程部署:校验和部署流程模型,记录流程模型快照。部署后流程可以执行

  3. 流程执行:从开始节点开始执行,到用户节点挂起或结束节点结束

  4. 流程提交:提交指定的用户任务,到下一个用户节点挂起或者结束节点结束

  5. 流程回滚:从当前用户节点开始回滚,回滚至上一个用户节点或者开始节点

  6. 执行轨迹追溯:查看流程实例的执行轨迹,可用于快照

为什么选择Turbo

1. 什么时候使用Turbo

业务支持模块化拆分、有序执行,并且有多变的编排诉求时,可以考虑采用Turbo作为底层引擎,同时可以配合使用 logicflow 进行可视化配置。

案例1:某团购售后流程

用户A在订单列表中选择订单,判断订单状态,如果状态为未发货,则直接跳转至退款申请页,如果状态为待收货则提示不支持售后,跳转至物流信息页,如果状态为已收货,则跳转至售后页填写售后信息并提交。

案例2:请假审批流程

员工A输入请假天数,判断请假天数是否大于等于3天,是的话由间接领导审批,否的话则由直属领导批准。

2. Turbo有什么不同

谈到流程引擎,当前市面上大部分是ActivitiFlowableCamunda等面向OA场景,功能强大且有比较完整的生态的工作流引擎(平台),同时因为OA复杂的场景,库表关联操作非常多,但是对于其它业务场景,引擎运维以及学习成本较高,性能不可避免有一定损失,不适用于C端场景。  

同时还有部分专注于纯内存执行、无状态的流程引擎,比如阿里的Compileflow,这类引擎中断后不可重入,不适用于人机交互场景,适用于执行业务规则。举例:N个人去ktv唱歌,每人唱首歌,ktv消费原价为30元/人,如果总价超过300打九折,小于300按原价付款。

Turbo的定位是兼容BPMN2.0的轻量级流程引擎(而非平台),支持可重入交互,主要负责提供稳定而高效的核心能力:流程定义流程驱动,而节点的具体执行由接入方实现,可以快速搭建面向各种场景的流程编排类系统或产品,接入简单,支持灵活扩展,引擎扩展能力通过插件或组件的形式进行补充,支持按需使用,大大降低了用户的运维以及学习成本。

3. 开源流程引擎对比

Activiti Camunda Compileflow turbo
核心表量 28 22 0 5
特性 中断可重入 ×
支持回滚 × ×
运行模式 独立运行和内嵌 独立运行和内嵌 内嵌 内嵌
兼容性 流程格式 BPMN2.0、XPDL、PDL BPMN2.0、XPDL、PDL BPMN2.0 BPMN2.0
支持脚本 JUEL、groovy python、ruby、groovy、JUEL QlExpress groovy
支持数据库 Oracle、SQL Server、MySQL Oracle、SQL Server、MySQL、postgre MySQL

关键模型

1 流程 (Flow)

定义了起点、终点以及起点到终点需要执行的活动、执行路径、执行策略。

2 流程实例 (FlowInstance)

一个流程可能会被多次执行,比如同一个场景的审批流是一个流程,每次有人提交审批这个流程都会被执行一次。流程每执行一次,对应一个流程实例。

3 流程元素 (FlowElement)

*考虑兼容性问题,流程元素设计参考了BPMN规范。

构成流程中的各种元素通称为流程元素 (FlowElement),包括节点 (FlowNode)和顺序流 (SequenceFlow)。

3.1 节点 (FlowNode)

3.1.1 事件节点 (EventNode)

例如:

  • 开始节点 (StartEvent):标识流程的开始;
  • 结束节点 (EndEvent):标识流程的结束;
3.1.2 活动节点 (ActivityNode)

例如:

  • 任务 (Task):需要处理的节点,例如:
    • 用户任务节点 (UserTask):使用方执行任务的节点,比如需要用户提交信息;
    • 系统任务节点 (ServiceTask):系统内部自行执行任务的节点;
  • 内嵌子流程 (SubProcess):将流程作为另一个流程的节点来处理;
  • 调用子流程 (CallActivity):与内嵌子流程不同的是,调用子流程拥有独立的模型存储,会产生新的流程实例
3.1.3 网关节点 (Gateway)

与SequenceFlow配合使用,用于描述SequenceFlow的执行策略。

例如:

  • 排他网关 (ExclusiveGateway):同一时刻的同一个实例中,根据指定输入,有且只有一条路径(SequenceFlow)被命中;

3.2 顺序流 (SequenceFlow)

记录节点之间的执行顺序,可以配置执行的条件conditions(比如用户点击了“同意”作为输入),conditions只有在与网关节点Gateway配合使用时生效,由Gateway决定conditions的执行策略。

快速开始

1.运行环境

  1. JDK1.8
  2. mysql

2.开发环境

  1. JDK1.8
  2. mysql
  3. maven 3.1+
  4. IntelliJ IDEA

maven

流程引擎核心功能集合

<dependency>
  <groupId>com.didiglobal.turbo</groupId>
  <artifactId>engine</artifactId>
  <version>1.0.0</version>
</dependency>

开发demo,非必须依赖

<dependency>
  <groupId>com.didiglobal.turbo</groupId>
  <artifactId>demo</artifactId>
  <version>1.0.0</version>
</dependency>

3. 配置必要信息

执行建表语句,在属性文件中配置属性信息

# 必要属性
spring.datasource.dynamic.primary=engine
spring.datasource.dynamic.datasource.engine.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.dynamic.datasource.engine.username=username
spring.datasource.dynamic.datasource.engine.password=password
spring.datasource.dynamic.datasource.engine.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.dynamic.datasource.engine.url=jdbc:mysql://127.0.0.1:3306/db_engine

4. 根据demo开始你的Turbo之旅吧

根据上文提到的turbo支持的特性,给出了两个例子,其中整体的流程如下图所示:

其中与业务相关的是流程的定义和流程的执行,跟着下面的两个例子来看流程引擎的使用:

Demo1:团购售后

代码:AfterSaleServiceImpl

Demo2:请假流程

代码:LeaveServiceImpl

注:例子使用两个service是为了封装sop,在实际开发中sop是有前端页面传递进入,并非是必须再次开发。

5. Turbo与LogicFlow交互demo

LogicFlow 是一款流程图编辑框架,提供了一系列流程图交互、编辑所必需的功能和灵活的节点自定义、插件等拓展机制。使用LogicFlow与Turbo接口交互可实现流程图创建,编辑,保存,发布功能,发布完成流程图即可参考第四部分文档,执行流程。

后端代码:FlowController FlowControllerTest

前端代码:https://github.com/Logic-Flow/turbo-client

使用文档:LogicFlowGuide

代码提供基本用法示例,使用方可以根据自己的业务场景参考使用

6. 新的节点类型CallActivity上线啦

千呼万唤的子流程它来了,着眼于内外部需求,我们新增了调用子流程节点,支持了同步单实例调用子流程

使用文档:CallActivityGuide

7. 联系我们

加入微信群

添加微信号:logic-flow 加入turbo用户群

turbo's People

Contributors

11stefanie avatar jameszhangxiao123 avatar liangchenhui avatar lthaoshao avatar lvyiyang avatar yoryor avatar zuokai666 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

turbo's Issues

请教性能

我看整体架构依赖数据库,有点担心性能是否能应对高并发?我理解应该设计为分层架构,分不同模块,按需引入。底层的执行引擎不依赖数据库,上层的应用层按需引入状态模块。

流程回滚

看介绍是可以回滚至开始节点和上一节点。支持回滚至中间的其他节点吗?

turbo-client启动报错,能帮忙解决下吗

TypeError: Cannot read properties of undefined (reading 'configure')
at D:\ideaworkspace\turbo-client\node_modules\vite\dist\node\chunks\dep-971d9e33.js:51435:18
at Array.forEach ()
at proxyMiddleware (D:\ideaworkspace\turbo-client\node_modules\vite\dist\node\chunks\dep-971d9e33.js:51423:26)
at createServer (D:\ideaworkspace\turbo-client\node_modules\vite\dist\node\chunks\dep-971d9e33.js:56584:25)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async CAC. (D:\ideaworkspace\turbo-client\node_modules\vite\dist\node\cli.js:688:24)

1.1.1 engine demo项目 测试用例缺少ei_flow_instance_mapping表定义

1.1.1版的engine 新增了一个ei_flow_instance_mapping 表, 不过在demo项目的test/resources/script/turbo-mysql-h2-ddl.sql 中缺少这个表定义, 导致运行DemoTest用例时失败.
微信图片_20230629193628
微信图片_20230629193632

同时希望在有表变化的版本中加上表变化声明, 方便用户从旧版本迁移到新版本

有流程设计器吗

有在线体验版吗
有配套的在线流程设计器吗
还是说 基于标准的 bpmn 格式

并行网关怎么实现?

看了源代码,发现getExecuteExecutor方法返回值是单个的,不符合并行网关的需求。是否有考虑到这个场景或者提供个解决思路?

[功能需求] 常见**式审批流/工作流需求

希望能支撑以下能力。作为流程引擎底层之外的,业务扩展包。

1、审批人驳回时能选择驳回到指定环节(activity/node),
场景:具体业务会驳回到对应环节,后面还会出报表统计岗位差错率
2、定义流程时可定义驳回不重走流程/重走流程
场景:一非常严格的场景会要求重走流程,一般不重走流程,毕竟不能麻烦领导审批2次。所以领导前是重走流程,领导后的不重走流程。驳回后再提交或审批会直接到领导这里来
3、审批人驳回时可选择驳回不重走流程/重走流程
场景:业务太灵活时再流程定义时指定的不准确,审批人自己去考虑,反正他的岗位职责就是审批这些因素
4、定义流程时可定义指定环节(activity/node)同一审批人自动审批
场景:领导可不虚幻审批两次。一般科室下面的人提交后第一个审批的就是科室经理,但是科室经理本身又是后面某个环节的负责人,那就会触发审批两次,因此第二次需要自动审批。

其他的什么发送模版消息,限定环节(activity/node)的审批人来源之类的简单的好实现,上面那种涉及流程驱动的不熟悉turbo不好整。

请求支持JDK 17,或者提供在JDK 17中运行的替代方案,谢谢~

近期我浏览了许多工作流框架,发现Trubo因其轻量级特性、最小依赖以及能够直接嵌入运行而给我留下了深刻的印象,这让它能够非常好地与LogicFlow配合使用。然而,遗憾的是,它目前不支持JDK 17,这对我当前的设置是一个明显的限制。

请问在不久的将来有没有可能使Trubo兼容JDK 17?或者是否有其他方法或思路,我可以在本地拉取代码后进行适配?期待您的回复,谢谢!

Question: 关于流程的执行逻辑

感谢开源,代码逻辑非常清晰,让我这个不写 java 的人也能完整的看完整个逻辑。但是不太清楚怎么和具体的业务关联起来。

比如下面这个点我非常疑惑:
流程直到用户节点挂起或者结束节点完成 就会停下,如果说 审批人请求 commitTask 之后,后面要经过很长的节点才会到达下一个挂起的节点,那这个审批人岂不是要一直等?

是否支持节点自动执行

目前看都是又外部触发流程流转,请问是否支持用户任务自动执行业务逻辑,然后流转到下一节点

如何在turbo中插入业务的处理逻辑

看了turbo的设计,很赞!但有个疑惑,turbo注重在流程的定义和执行,但是看了源代码,貌似框架本身也没有提供用于流程节点去绑定业务处理逻辑的扩展点?那如果这种没有可以统一的入口定义了,后续拖拉拽来编排业务逻辑,如何实现标准化的管理呢?l可能的话,能否公布下turbo后续要支持的特性和预期时间呢?

JDK17不兼容报错

Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make private static java.lang.invoke.MethodHandles$Lookup jdk.proxy2.$Proxy118.proxyClassLookup(java.lang.invoke.MethodHandles$Lookup) throws java.lang.IllegalAccessException accessible: module jdk.proxy2 does not "opens jdk.proxy2" to unnamed module @1afd44cb
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354) ~[na:na]
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297) ~[na:na]
at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:200) ~[na:na]
at java.base/java.lang.reflect.AccessibleObject.setAccessible(AccessibleObject.java:130) ~[na:na]
at org.codehaus.groovy.reflection.CachedClass$3$1.run(CachedClass.java:86) ~[groovy-all-2.3.7.jar:2.3.7]
at java.base/java.security.AccessController.doPrivileged(AccessController.java:318) ~[na:na]
at org.codehaus.groovy.reflection.CachedClass$3.initValue(CachedClass.java:81) ~[groovy-all-2.3.7.jar:2.3.7]
at org.codehaus.groovy.reflection.CachedClass$3.initValue(CachedClass.java:79) ~[groovy-all-2.3.7.jar:2.3.7]
at org.codehaus.groovy.util.LazyReference.getLocked(LazyReference.java:46) ~[groovy-all-2.3.7.jar:2.3.7]
at org.codehaus.groovy.util.LazyReference.get(LazyReference.java:33) ~[groovy-all-2.3.7.jar:2.3.7]
at org.codehaus.groovy.reflection.CachedClass.getMethods(CachedClass.java:250) ~[groovy-all-2.3.7.jar:2.3.7]
at groovy.lang.MetaClassImpl.populateMethods(MetaClassImpl.java:361) ~[groovy-all-2.3.7.jar:2.3.7]
at groovy.lang.MetaClassImpl.fillMethodIndex(MetaClassImpl.java:340) ~[groovy-all-2.3.7.jar:2.3.7]
at groovy.lang.MetaClassImpl.initialize(MetaClassImpl.java:3225) ~[groovy-all-2.3.7.jar:2.3.7]
at org.codehaus.groovy.reflection.ClassInfo.getMetaClassUnderLock(ClassInfo.java:210) ~[groovy-all-2.3.7.jar:2.3.7]
at org.codehaus.groovy.reflection.ClassInfo.getMetaClass(ClassInfo.java:241) ~[groovy-all-2.3.7.jar:2.3.7]
at org.codehaus.groovy.reflection.ClassInfo.getMetaClass(ClassInfo.java:251) ~[groovy-all-2.3.7.jar:2.3.7]
at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.getMetaClass(MetaClassRegistryImpl.java:259) ~[groovy-all-2.3.7.jar:2.3.7]
at org.codehaus.groovy.runtime.InvokerHelper.getMetaClass(InvokerHelper.java:855) ~[groovy-all-2.3.7.jar:2.3.7]
at org.codehaus.groovy.runtime.callsite.CallSiteArray.createPojoSite(CallSiteArray.java:122) ~[groovy-all-2.3.7.jar:2.3.7]
at org.codehaus.groovy.runtime.callsite.CallSiteArray.createCallSite(CallSiteArray.java:163) ~[groovy-all-2.3.7.jar:2.3.7]
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45) ~[groovy-all-2.3.7.jar:2.3.7]
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108) ~[groovy-all-2.3.7.jar:2.3.7]
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:112) ~[groovy-all-2.3.7.jar:2.3.7]
at org.codehaus.groovy.control.customizers.ASTTransformationCustomizer.findASTTranformationClass(ASTTransformationCustomizer.groovy:202) ~[groovy-all-2.3.7.jar:2.3.7]
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:577) ~[na:na]
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90) ~[groovy-all-2.3.7.jar:2.3.7]
at org.codehaus.groovy.runtime.callsite.StaticMetaMethodSite$StaticMetaMethodSiteNoUnwrapNoCoerce.invoke(StaticMetaMethodSite.java:148) ~[groovy-all-2.3.7.jar:2.3.7]
at org.codehaus.groovy.runtime.callsite.StaticMetaMethodSite.callStatic(StaticMetaMethodSite.java:99) ~[groovy-all-2.3.7.jar:2.3.7]
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallStatic(CallSiteArray.java:53) ~[groovy-all-2.3.7.jar:2.3.7]
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callStatic(AbstractCallSite.java:157) ~[groovy-all-2.3.7.jar:2.3.7]
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callStatic(AbstractCallSite.java:169) ~[groovy-all-2.3.7.jar:2.3.7]
at org.codehaus.groovy.control.customizers.ASTTransformationCustomizer.findPhase(ASTTransformationCustomizer.groovy:224) ~[groovy-all-2.3.7.jar:2.3.7]
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:577) ~[na:na]
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90) ~[groovy-all-2.3.7.jar:2.3.7]
at org.codehaus.groovy.runtime.callsite.StaticMetaMethodSite$StaticMetaMethodSiteNoUnwrapNoCoerce.invoke(StaticMetaMethodSite.java:148) ~[groovy-all-2.3.7.jar:2.3.7]
at org.codehaus.groovy.runtime.callsite.StaticMetaMethodSite.callStatic(StaticMetaMethodSite.java:99) ~[groovy-all-2.3.7.jar:2.3.7]
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallStatic(CallSiteArray.java:53) ~[groovy-all-2.3.7.jar:2.3.7]
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callStatic(AbstractCallSite.java:157) ~[groovy-all-2.3.7.jar:2.3.7]
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callStatic(AbstractCallSite.java:169) ~[groovy-all-2.3.7.jar:2.3.7]
at org.codehaus.groovy.control.customizers.ASTTransformationCustomizer.(ASTTransformationCustomizer.groovy:178) ~[groovy-all-2.3.7.jar:2.3.7]
at org.codehaus.groovy.control.customizers.ASTTransformationCustomizer.(ASTTransformationCustomizer.groovy:186) ~[groovy-all-2.3.7.jar:2.3.7]
at groovy.text.markup.MarkupTemplateEngine.(MarkupTemplateEngine.java:84) ~[groovy-all-2.3.7.jar:2.3.7]
at org.springframework.web.servlet.view.groovy.GroovyMarkupConfigurer.createTemplateEngine(GroovyMarkupConfigurer.java:160) ~[spring-webmvc-5.3.23.jar:5.3.23]
at org.springframework.web.servlet.view.groovy.GroovyMarkupConfigurer.afterPropertiesSet(GroovyMarkupConfigurer.java:153) ~[spring-webmvc-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1863) ~[spring-beans-5.3.23.jar:5.3.23]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1800) ~[spring-beans-5.3.23.jar:5.3.23]
... 16 common frames omitted

如何扩展并行网关

看了流程执行逻辑里,不管是getUniqueNextNode方法还是calculateNextNode方法,都是需要明确走到下一个确定的节点,那如何扩展并行网关

子流程的实现方案

看了下有subprocess的对象,但是没有相关的实现方案和单测,请问有子流程的实现方案吗

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.