基于 QWorker 的多线程编程 – 工作流控制

工作流(WorkFlow)是一个被炒了很久的东西,并出现了一些工作流引擎。那么,QWorker 是不是也能做一些这方面的工作呢?答案是显然的,QWorker 本身基于作业的特性,决定了它很适合完成一些普通的工作流管理任务。

工作流引擎实际上实现了两个部分的工作:流程的控制和作业的执行。工作流程的控制实际上可以分成顺序执行、条件跳转(含重复执行)两大类,而工作的执行则和我们普通的作业没有任何区别。所以,当我们用 QWorker 做为一个工作流管理的基本引擎时,我们需要做的一件很重要的事情就是如何来完成工作流控制部分。

一个最简单的工作流控制的实例是顺序执行的多步作业,这个我们直接通过创建 TQJobGroup 的顺序执行的作业分组实例即可达到目的。

稍微复杂一点的工作流控制实例是然后是顺序执行的多步作业,但是某些步骤我们会由于某些原因跳过执行。这种情况下,我们只需要在上面的基础上,在作业执行代码中,前置一些简单的条件判断处理,决定实际的作业执行代码是否执行即可达到目的。当然,考虑到流程控制的后期可定制性,显然使用类似于 PaxScript、FastScript 等脚本引擎与作业结合,能够更好的完成后期定制工作。

最复杂的工作流程控制实际上牵涉到循环的重复多步作业。比如:我们提交一个申请给上级主管部门,主管部门给出反馈意见,让我们修改申请,我们修改后再次提交上级主管部门审核,重复上述流程,直到主管部门通过或者直接驳回申请。这样一个重复的作业过程,在 QWorker 中,我们实际上可以通过信号来完成这类复杂的作业的控制的。以上面我们提到的样本为例子,我们如果以 QWorker 为流程的基本引擎,那么我们定义几个信号:

1、Request.Post – 当我们向上级提交完申请后触发;

2、Request.EditNeeded – 当上级给出修改意见后触发;

3、Request.Accept – 当上级通过我们的申请后触发;

4、Request.Deny – 当上级驳回我们的申请后触发;

5、Request.Discard  – 当我们决定放弃申请时触发;

那么,现在事情的处理就相当简单了:

1、我们有个一申请编辑的作业,它用来编辑申请内容。当我们第一次提交申请时,或者收到 Request.EdtNeeded 信号时触发。在编辑完成后,我们有两个选择,一个是我们觉得我们的申请有问题或者不再需要申请了,那么我们就触发一个 Request.Discard 信号,触发放弃申请的作业,另一个是我们确认申请内容没有问题了,触发一个 Request.Post 事件,将申请提交给上级。

2、我们的上级有一个审核作业,它在收到下级的 Request.Post 信号时触发,根据上级做出的审核结果,分别触发下级的 Request.EditNeeded、Request.Accept 或 Request.Deny 三个信号之一。

3、下级分别有两个作业对应于 Request.Accept 和 Request.Deny 两个信号,用以在上级通过和拒绝申请时,提供必要的处理。

这样子,我们就形成了一个事实上的很复杂的业务流程处理逻辑。实际生活中,再复杂的业务逻辑也可以通过上述方式进行处理。

我们再考虑工作流控制中的分支和归并问题。一个作业可能分割出多个子作业,然后在各个子作业完成后,归并到同一个部门去汇总归档。这个问题的处理实际上通过信号我们一样可以完成,作业分隔我想不用赘述,直接分隔成多个作业就好了,作业合并多说一句,简单的就在每个子作业完成后,触发一个归并请求信号如叫 Jobs.MergeNeeded ,然后在这个信号的响应作业中去检查是否所有子作业都执行完成了,如果完成了,就触发一个实际的合并信号,如 Jobs.DoMerge来执行实际的合并作业。

实际上实现一个完整的工作流控制,需要编写的代码并不少,上面讨论中忽略了信号在网络中传递的过程,实际上,它是必不可少的环节。但我们讨论的主要是利用 QWorker 作业一个流程控制的基础引擎的实现方式,所以,我们省略了具体的实现,而只是讨论了理论上应该如何实现。一个完整的工作流引擎还需要做许多工作,不是本文讨论的范围。当然,你可以用 QWorker + PaxScript + DIOCP 实现一个作业调度、脚本化和网络传送,从而实现一个真正完整的工作流引擎。

分享到: