在流程执行的过程中既有成功的情景,也会有失败的情景.如果某个流程中执行失败了,应该采取哪些处理措施呢?这些处理措施是不是有最佳实践呢?答案就是工作流技术中的异常模式。
异常并不是工作流管理系统才有的,所有软件信息系统都有异常, 先来看看信息体统中的常规异常,有别于后续要介绍的工作流异常。常规异常,实际上就是指我们日常开发中所遇到的各种程序异常和业务异常。常规异常对于IT人员并不陌生,我们几乎每天都在与各种程序语言中的异常打交道,例如Java语言中各种各样的Checked Exception和UnChecked Exception。对于常规异常,不同的语言提供了不同的处理机制。
一个稳定健壮的应用系统是离不开良好的异常处理设计与实现的。程序语言只提供了最基本的异常处理机制,在实际的开发中,往往需要设计者给出更易用、更友好的、统一的异常框架设计。
1.工作流异常的概念
那么什么是工作流异常呢?工作流异常是指对理想的协同处理过程(利用已有资源,以一种最佳的方式来达到任务的要求)产生的任何偏移,包括活动执行时遇到的错误、代理人之间的通信错误、对任务和资源的变化缺少支持等。即工作流在协同处理的过程中,出现的任何偏离了正常或期望的行为都是工作流异常行为。例如,工作流的正常期望是流程的各个活动能够顺利执行结束,为顾客输出他想要的价值,如果不能得到这个结果,则属于工作流异常。
需要注意的是,相当多情况下工作流异常需要在人工参与的情况下进行传播,而非自动传播,并且在异常处理完成后,过程应该从异常发生处继续执行,这是与高级编程语言异常处理模式的很大不同。
2.工作流异常的分类
按照异常的预测程度分为可预测异常和不可预测异常
a)可预测异常:可以预见的并且已经定义好异常处理器的工作流异常,通常对出现的异常情况有充分的了解,并明确定义了异常处理过程;
b)不可预测异常:在模型定义阶段无法预知的异常情况,通常需要在异常发生时通过人工参与处理该类异常。
按照触发源分为外部异常和内部异常
a)外部异常:由参与工作流执行的系统外部因素所引起的异常,如操作系统、网络、数据库、应用软件和硬件设备等故障所产生的异常。
b)内部异常:由工作流管理系统自身印发的异常,如不能为活动指定执行者、不能获取活动执行所需的资源、活动错过截止期等。
对于按照触发源划分,美国乔治亚大学的ZongweiLuo与Amit Sheth等人又进行了更为细致的划分,产生了以下工作流异常分类:应用异常、工作流异常、基础结构异常。
应用异常:指由任务的执行者通过这个任务项参与到业务系统中,进行业务操作。此时,任务执行者如果由于误操作(例如输入了错误的参数)或故意执行非正常期望的操作(例如进行驳回),从而导致工作流不能正常执行,称之为应用异常。工作流引擎还会在执行的过程中自动调用业务系统提供的接口或服务(有可能位于ESB中),如果业务系统提供的接口或服务发生异常(例如不可调用),同样会引起工作流不能正常执行,此时也称之为应用异常。实际上,应用异常可以定义为由工作流的应用者本身所引起的异常。
工作流异常:指由工作流系统本身直接激发的异常,又分为系统异常和用户定义异常。前者包括时间异常(工作流实例违反时间限制,如任务运行时间超过给定期限)、资源异常(资源不可用,例如生成任务时找不到建模期定义的任务执行者)、数据异常(工作流相关数据违反其约束条件)。后者实际上就是指上文提到的可预测异常,也就是说,由工作流的设计者在建模期对于可预测的工作流系统本身的多个异常进行定义,并且为每个异常定义一个异常处理,在异常发生时做出相应的处理。
基础结构异常:指由应用服务器、数据库、网络、操作系统、硬件设备等基础设施所引起的异常。
从技术角度来看,上面三层异常模型应该是最容易理解与应用的。从工作流产品设计和实现的角度,我们也认为是最清晰的。当然除了上述两个主要的分类方式以外,还有一些其他的分类方式,按照工作流可探测的异常事件可分为:
工作项执行失败
超时
资源不可用
外部触发
违反约束
3.工作流异常的处理
忽略策略:工作流的某个活动在执行过程中,主要行为已经执行完毕。此时如果出现异常,但是此异常所产生的行为不影响后续活动的执行,那么此时就可以采用忽略策略。忽略此异常,让活动继续执行,直至转移到其后续活动。
放弃策略:若在某个活动的执行过程中,出现的异常使得整个活动不能继续执行下去,此时就只有采取放弃策略。实际上,这一策略的本质就是回滚。对于工作流的某个原子活动的某次状态转移来讲,所有的行为(活动本身的执行、此活动节点绑定的事件或服务的执行、任务的分配等)都处于一个原子事务中,因此失败即回滚。
替换策略:在工作流执行过程中,若某个活动执行时出现异常使其不能继续,但存在另外一个可选的活动或另外一条执行路径使得程序可以继续,此时就可以采用替换策略。
补偿策略:补偿是发生在两个原子事务甚至多个原子事务之间;或者说,发生在事务递交之后。在业务操作已经跨越了多个原子事务之后,如果在最后一个事务处发生失败,需要消除对以前的一个或多个业务操作所产生的影响,则必须执行补偿策略。
重试策略:在工作流活动执行的过程中,对于出现异常的活动重新尝试执行,直到活动执行成功,或者达到最大重试次数,这种策略称之为“重试策略”。重试策略一般应用在异步执行的场景中,因为不知道什么时候重试成功,所以不能一直同步等待。
工作流模型定义了其组成任务(包括活动与子过程)的各种执行属性。为了满足异常处理的要求,我们在工作流模型中加入任务的事务特征和异常处理属性定义。表1简要描述了这些属性,其中包括任务执行失败后的回退(Rollback)属性,由于并非所有任务都是原子性的,所以在任务执行失败后需要取消任务失败所产生的影响;任务执行完成后的补偿(Compensate)属性,可以在后向恢复时将已经完成的影响消除,恢复到未执行状态;任务失败后的重试(Retry)属性;以及该任务所有可以引发的异常和提供的异常处理过程。
除了工作流异常处理的五个最基本策略,目前在工作流异常领域主要有三个基本方法来针对具体的应用。
失败补偿法:这种方法的基本思想就是每一个活动对应一个补偿活动,这个补偿活动在语义上就是消除(undo)对已执行的活动所产生的影响。当一个活动执行失败时,就启动执行补偿活动(通常是前面活动的逆执行),直到找到一个分支点,使整个过程能继续向前执行。
ECA规则法:事件描述了潜在异常情况的出现,条件用来表示当事件发生时不同的处理前提,动作是指对异常事件应做出的反应。ECA规则要求每一具体的异常类别建立相应的规则(也称为触发器),根据发生的异常事件,在满足一定的条件的前提下去调用相应的动作(活动、子程序、人工干预等)。
基于知识库法:先对异常分类,定义每一类别的特征,建立起知识库;每个异常有一种“异常探测”处理模板来捕获异常,通过自顶向下的启发式搜索找到异常的原因,再采用相应的过程去处理。这种方法与ECA规则类似,不过这种方法为人机交互处理异常(选择合适的处理方法)提供了更多的信息。
4. 异常处理模式
在工作流当中部分短事务可以采用回滚策略,但对于长事务,则必须采用补偿策略来解决。补偿一般都是基于事件驱动的,即在异常(此处异常是广义上的,如流程驳回也可以称之为异常)发生时,通过异常事件去触发执行驳回事件。驳回事件由业务系统提供,以数据库的CRUD(Create、Read、Update、Delete)操作为例,插入的补偿操作是删除、更新的补偿操作是另一次更新。一句话,“原有业务操作的逆操作即定义为补偿操作”。
相当多的情况下,异常处理过程需要人工参与进行。考虑到人员在工作流系统中的严格角色的和权限定义,单靠部分参与者可能无法完成一个异常处理过程,二频繁的异常传播又会导致处理过程复杂,效率下降。所以在不进行异常传播时,可以采用组织层次的异常处理协调机制,实现多人参与的异常处理模式。