lecher
2020-11-17 04:04:45 +08:00
就是一份数据,数据实体同时记录工作流状态,业务处理的流程同时修改实体对应的数据并提交到数据库。
最直白的工作流描述方式类似这样
状态 1: 响应事件 a,b,c
状态 2: 响应事件 d,e,f
状态 3: 结束
处理的过程无非是,收到对 entity1 发送的事件 x,从数据库中将 entity1 查询出来,进行状态事件表查询,跳转到要执行的业务处理代码,然后服务执行这份代码对 entity1 的数据做处理,处理完后跳转到状态 y 并提交当前 entity1 经过处理后的数据到数据库,等待下一个事件。
接着拆解一下事件的类型:
1.外部服务发送过来的请求
2.其它工作流发送过来的事件
3.延时 /定时触发的事件
可以看出来,需要有不同的协议来适配对应的事件转换:
1.提供服务端对外接口接收外部请求,并转换成事件
2.不做转换
3.提供延时队列服务收发延时任务,并在指定时间发起对应的事件
再看一下收到事件该怎么处理:
1. 根据事件参数中的 entityName, entityID 查出数据
2. 将数据 loaded 到 class 中
3. 调用事件对应的 method,执行对应的业务代码
4. method 之后需要更新下一阶段的状态标识到 class 的字段上
5. 将当前 entity 的所有业务数据连同状态标识一并提交到数据库保存
可以推测一下实现方式:
1.从数据库 load 数据出来
2.使用这份数据去 new 一个 class
3.带着事件参数去 call class.method(params)
4.序列化 class 的数据,提交到数据库
这需要运行的语言支持什么特性?
1. 可以根据字符串类名实例化一个 class
2. 可以根据字符串方法名调用一个 class.method
3. 方便的序列化、反序列化数据,最好是无缝与 json 形式的数据转换
4. 能用简洁的语法描述业务处理
不管原始业务是用什么语言写的,这些业务处理代码都可以在同一套服务进程内运行,因为本质上这就是一个请求-处理-保存数据-返回结果的流程。业务代码与正常的网络请求处理毫无差别。
接着抛开实现细节,以请假审批为例子看看如何使用代码描述一个工作流的处理是易于阅读的。
方式 1
class 请假 {
public 待发起(event, params){
if (event === 发起){添加延时任务通知超时,发出审批通知;next(待审批)}
if (event === 放弃){next(关闭)
}
public 待审批(event, params){
if (event === 同意){更新年假业务数据;next(通过)}
if (event === 超时了){发送超时通知;next(超时)
}
public 超时(event, params){
if (event === 重新发起){修改业务数据;next(待审批)}
if (event === 放弃){更新相关数据;next(关闭)
}
public 通过(event, params){
// 空处理,仅作状态记录,不会再响应其它事件
}
public 关闭(event, params){
// 空处理,仅作状态记录,不会再响应其它事件
}
}
方式 2
class 请假 {
public process(){
待发起:
event = this.event
if (event === 发起) { 更新业务数据;goto 待审批}
if (event === 放弃) {goto 关闭}
待审批:
event = this.event
if (event === 同意) { 更新业务数据;goto 通过}
if (event === 超时了) {goto 超时}
超时:
...
通过:
...
关闭:
...
}
}