基本WWF的研究已经有一段时间了,在Windows SDK Documentation中的有关WWF的资料也看了个差不多。现在理论上的东西基本上没有什么问题,那么问题就在于如何去应用了。从网上查了一下,这方面的案例很少,也许非WWF的其它工作流引擎的应用可能会多一些,但我没有去查。为此我自己进行了一些探索,也不知摸索的对不对,但自己感觉能够走的通,所以写下此文。可能会存在一些弯路,还望有识之士给以点评。这里以顺序工作流进行说明。
首选是持久化与锁定问题及DelayActivity过期执行的问题:
借助于WWF提供的设计器我们可以轻松的设计出一个工作流,并使之能够运行。如果活动由同一个进程来参与这是没有问题的,但工作流可能需要多个人的参与,这就需要将工作流进行持久化了。持久化要考虑的事情很多,如持久化的存储,锁定,及对DelayActivity的影响等等。
WWF提供了WorkflowPersistenceService和SqlWorkflowPersistenceService两个类来实现持久化。但WorkflowPersistenceService是一个抽象类,需要自己去实现,网上有和SDK中有有关文件持久化的实现,但不是一个完整的实现。SqlWorkflowPersistenceService是一个持久化到数据库的完整实现,不过只能用于Sql Server。为了能够使用SqlWorkflowPersistenceService,数据库还需要启动DTC服务。
我曾经对SqlWorkflowPersistenceService的锁定机制存在疑虑。在SDK中我有这样的理解,如果工作流引擎加载工作流实例时,如果加载成功它会锁定,这样其它引擎就不能加载这个工作流实例了。当工作流实例保存回数据库后便解除锁定状态,这样其它引擎便可加载该工作流实例了。我假设了一种情况,当加载工作流实例的进程突然死掉(如掉电),则数据库的锁定状态是不是永远都不能解锁了。对此我进行了研究,在SqlWorkflowPersistenceService的构造函数中有一个参数instanceOwnershipDuration,这个参数的意义是什么?SDK中没有直接给出一个详细的说明,但却在其它地方隐含的说明了(并没有提及到instanceOwnershipDuration这个参数名)。根据我的理解此参数它实际上指明了锁定工作流实例的时间限制。我们依据现实情况去估计一个工作流实例在某一个环节处理所用的时间进行设置,如10分钟。如果处理时间超过这个值则会被其它引擎自动解锁,也就是说解锁可以由其它引擎来进行而不依赖于当前的进程。这是如何实现的呢?
我看了一下服务于SqlWorkflowPersistenceService的数据库WorkflowPersistenceStore,里面有一张表InstanceState,这个表里记录着工作流的实例,其中有一个OwnedUntil字段,它记录了该工作流实例锁定的到期时间,当引擎加载一个工作流实例时,它会将当前时间加上SqlWorkflowPersistenceService构造函数中的instanceOwnershipDuration参数指定的时间,并把相加的时间存放到OwnedUntil字段里。同时数据库里还有一个存储过程UnlockInstanceState,其它的工作流引擎就是用此存储过程来解锁被锁定的工作流实例。这个过程是引擎自动完成的,我们所要做的就是加载一个我们需要的工作流。
我们再来看一下DelayActivity,这是一个提供延时处理的活动。假设一下,当一个活动处理于Idle状态,并且工作流实例的UnloadOnIdle被置位。那么我们就需要延时到达后(注意这个“后”字,即延时过后什么时间加载都是可以的。)提供工作流实例继续运行的方法。SDK中有一个有关自定义持久化服务的一个例子,它对该功能进行了描述,但它没有考虑工作流实例被不同的进程进行处理时的延时修正问题。SqlWorkflowPersistenceService为我们提供了所有的这一切:在InstanceState表中有一个NextTime字段,便是用于修正延时时间用的。SqlWorkflowPersistenceService的构造函数中还有一个参数LoadingInterval,此参数可以使引擎在多少时间间隔内去检测那些超时的工作流实例,如果超时了则自动进行加载并运行。
请注意instanceOwnershipDuration和LoadingInterval参数的使用,否则可能会出现你不希望发生的情况!当instanceOwnershipDuration和LoadingInterval的值设的足够小,如将instanceOwnershipDuration的值设为0,LoadingInterval的值设为1,则一个超时的工作流实例可能被多个工作流引擎同时加载……。因为每个加载者在进行加载的时候都不进行锁定,所以会发生这样的情况。切记!
SqlWorkflowPersistenceService一般情况下在工作流实例运行完成后将其自动从数据库中进行删除以释放占用的空间。但当进程非正常退出时可能会将数据库的工作流实例的NextTime字段的值设为最大值,即永远都不会再次被加载,当然也不会消除所占用的空间,这种情况发生的概率很小(这是我偶然发现的,当工作流实例完成,但还没有进行清除时便结束工作流的运行就会发生这样的情况!)。
WWF的一些技术细节与应用体会(一)
WWF的一些技术细节与应用体会(二)
Rehosting WWF 设计器 之运行时定制活动的外观
Rehosting WWF Designer 之定制活动的外观
Rehosting WWF Designerp之从工具箱拖动活动到设计器上
Rehosting WWF 设计器