-
[*]bugfix: 修复节点去重时仍然会执行当前节点的回调的问题 -
[+]bizId根据ownSign隔离的改造改动到
pikachu_p和pikachu_s的表结构,具体请看升级方案文档 -
[+]模块现在可以可选依赖别的模块比如
ScheduleModule就是可选依赖PersistModule的,当存储使用ZK时不会传递依赖进来,而使用DB时需要显式依赖 -
[*]修改数据库操作中所有对gmt_create和gmt_modified字段的赋值都使用数据库时间 -
[+]在PersistMachine.apply(...)时,新的特定的运行时异常可能抛出如果数据库中
bizId对应的流程记录存在,并且和apply方法给定的模板名或版本不一致时,将会抛出com.tmall.pokemon.pikachu.persist.exception.ProcessAlreadyExistException -
[*]重构了Machine和PersistMachine的构造部分,现在构造方法是protected的了这意味着不再允许用
new关键字来实例化Machine和PersistMachine请使用对应的
apply方法Machine.apply(...)和PersistMachine.apply(...) -
[*]bugfix: 修复持久化流程存储模板版本为0的问题有自动fix的接口可以调用 -
UpdateHelper.fixDefinitionVersion() -
[+]script标签现在支持异步执行使用
<script ... async="true">...</script>来标记异步执行这一段脚本 -
[*]修改模块依赖方式现在使用
Module.require(new ModuleDefine[]{PersistModule.module(), ScheduleModule.module(), ...})这样的语法初始化模块 -
[+]调度模块加入ScheduleModule: pikachu-schedule
-
[+]增加从Machine和PersistMachine中获取信息的方法在
Machine和PersistMachine中共有的getProcessName()和getProcessVersion()获取流程名和流程版本号在
PersistMachine中getBizId()获取业务ID -
[*]现在PersistMachine.apply(bizId: String)在数据库中找不到对应流程记录的时候会抛出特定异常而不再是NPE抛出
com.tmall.pokemon.pikachu.persist.exception.ProcessNotFoundException -
[+]现在模板和流程实例已经可以根据不同的标识隔离,这个特性可用来做环境隔离或者应用隔离给
pikachu_d和pikachu_p两个表增加own_sign字段,同时在对应的DAO方法里增加ownSign参数ownSign在CoreModule中配置 -
[+]在Machine中新增从上下文中移除键值对的方法machine.removeContext(key),移除指定key的键值对,如果有值则返回值,否则返回null -
[+]在PersistMachine执行持久化流程时,现在可以持久化和反持久化上下文中的null值 -
[*]修改调用MVEL Script的方式,使得在MVEL Script中可以支持赋值操作之前无法在模板中配置的脚本使用赋值操作,现在已经支持
需要注意的是对上下文中存在的变量进行赋值的作用域仅在脚本范围内,并不会进入上下文中
-
[*]现在创建流程获取流程模板时抛出的异常更加明确了,有利于开发阶段的排查之前不论出现什么错误都是抛出
NullPointerException,现在则会将解析时产生的SAXException和IOException抛出了 -
[+]增加pikachu_p表并在pikachu_s表中增加字段status标识状态现在可以只通过bizId就获取到已经持久化了的流程的状态
PersistMachine.apply(bizId)现在不再物理删除被回滚丢弃的节点,而是标记为rollback,同时支持单节点事务和去重
-
[*]去除<p-start> <p-state> <p-event>三个持久化节点,通过PersistMachine提供持久化支持不再使用节点扩展来支持持久化,而是在引擎中扩展持久化
-
[-]删除了pikachu-j这个module暂时不再支持从java方式进行扩展(因为考虑到短期内不会有业务方的自扩展需求),同时对Java足够友好的部分API现在直接放在scala实现类中
-
[*]修改了初始化方式使用
Module.require()方式来统一管理模块依赖和初始化,不再使用模块单独的init方式
这是一个状态机,核心就是状态之间的顺序流转,从一个状态指向另一个状态
状态分为两种,自动状态和手动状态。自动状态正常情况下不会停留,而手动状态会暂停并等待唤醒
pikachu.version = 1.0.2-SNAPSHOT
下文如无特殊说明,示例代码都是Java
-
引入依赖
<dependency> <groupId>com.tmall.pokemon.pikachu</groupId> <artifactId>pikachu-core</artifactId> <version>${pikachu.version}</version> </dependency> -
创建流程
流程通过
.xml格式定义,下面是一个简单的例子<!-- 流程总是由一个process标签定义,内部嵌套复数的节点元素来描述流程的流转 --> <process name="process"> <!-- 流程节点:start 在默认Parser实现中会被解析为第一个节点 --> <start name="i'm start"> <paths> <path to="state1"/> </paths> </start> <!-- 流程节点:state 最普通的节点,可以执行el脚本 --> <state name="state1"> <paths> <path to="state2" expr="goto==2"/> <path to="state3" expr="goto==3"/> </paths> </state> <state name="state2"> <invokes> <!-- 脚本执行的支持,通过pojo和springBean都可以 --> <script return="a" pojos="test.TestBean -> test, test.TestBean2 -> test2"> test2.testMethod(test.testMethod(i)) </script> <!-- 可以通过expr表达式来判断是否执行这段script --> <script return="a" pojos="test.TestBean -> test, test.TestBean2 -> test2" expr="test2.judge()"> test2.testMethod(test.testMethod(2)) </script> <!-- async属性使script异步执行,默认为false,在异步下return属性是无效的 --> <script pojos="test.TestBean -> test, test.TestBean2 -> test2" async="true"> test2.testMethod(test.testMethod(2)) </script> </invokes> <paths> <path to="end"/> </paths> </state> <state name="state3"> <paths> <path to="end"/> </paths> </state> <state name="end"/> </process>节点元素除了引擎内置的少量类型,也可以进行自定义和扩展
-
调用流程
在任何流程开始执行之前,你需要初始化整个引擎。视需要添加的扩展功能不同,需要初始化的动作可能会增加
import com.tmall.pokemon.pikachu.core.Module ... Module.require();使用
Machine创建和驱动流程import com.tmall.pokemon.pikachu.core.Machine ... Machine m = Machine.apply("process"); // 放入执行需要的上下文 m.addContext("i", 1); // scala有更加scala的api来操作上下文 m.run(); // 获取执行后的上下文 m.context("i"); // 或者获取执行后的流程当前位置 m.getCurrentStateName(); // scala m.currentStateName
在应用初始化阶段使用'Module.require()'初始化pikachu并加载需要的模块
Module.require(); // 初始化pikachu 只加载默认的CoreModule
Module.require(new ModuleDefine[] {PersistModule.module(), ...}); // 加载入参数组中的所有Module
// scala的api Module.require(PersistModule, ...)
tips:Module.require()方法应该被调用且只被调用一次。即便不依赖任何模块也要调用,在空调用中CoreModule会被默认加载
现在pikachu的模块组织
-
pikachu-core<dependency> <groupId>com.tmall.pokemon.pikachu</groupId> <artifactId>pikachu-core</artifactId> <version>${pikachu.version}</version> </dependency>包含的module
-
核心模块
com.tmall.pokemon.pikachu.core.CoreModule提供核心服务,是必须的。在这里实现了默认的获取流程模板并解析执行的行为
-
默认实现中流程模板应该放在哪里?
在
CoreModule的默认实现中,流程模板按照名字中.替换为/并加后缀.xml的方式从classpath下获取。也就是说当你调用Machine.apply("pokemon.process.testProcess")时,会从/pokemon/process/testProcess.xml获取流程定义文件 -
CoreModule中有些什么配置?你可以
- 指定一个spring的
ApplicationContext给引擎,让引擎可以获取到被spring管理的bean - 指定一个身份标识
ownSign,为后续需要隔离不同的应用或者环境留下配置,默认为default - 指定一个自定义的或内置的
Parser来改变引擎获取和解析流程定义的行为 - 增加或替换自定义的或内置
State来支持新的节点,或者扩展节点的行为
- 指定一个spring的
-
-
-
pikachu-ext<dependency> <groupId>com.tmall.pokemon.pikachu</groupId> <artifactId>pikachu-ext</artifactId> <version>${pikachu.version}</version> </dependency>包含的module
-
持久化模块
com.tmall.pokemon.pikachu.persist.PersistModule提供带版本支持的数据库流程模板获取,扩展自
Machine的PersistMachine提供回滚和持久化流程状态及路程的特性-
PersistModule的配置在
Module.require(...)之前,需要使用PersistModule.setDataSource(ds)给出一个数据源三个数据库表名称的配置项:
tableNameP, tableNameS, tableNameD,让你可自定义表名称usePersistParser配置项用以决定是否使用持久化带版本支持的数据库流程模板。默认为true,但是在开发阶段false会更方便 -
PersistMachine的使用所有通过
PersistMachine执行的流程都会被持久化通过
PersistMachine.apply(bizId, processName)创建一个新的持久化Machine通过
PersistMachine.apply(bizId)获取一个已经存在的持久化Machine通过
rollback和rollbackTo方法来回滚一个节点或者回滚到指定节点 -
持久化带版本支持的数据库模板方式
在
com.tmall.pokemon.pikachu.persist.DefinitionHelper中有三个接口分别用于自动部署一个模板、部署一个模板为指定版本以及指定已经存在的某版本为该流程的默认版本典型的使用方式是在修改模板后每次都使用自动部署的方式生成一个新版本并自动成为默认版本,当此版本有问题时使用设置默认版本的接口回到之前的版本
-
-