您的位置:首页 > 其它

WWF的一些技术细节与应用体会

2008-01-25 10:28 211 查看
(一)

原文出处:http://www.cnblogs.com/llxxbb/archive/2007/01/16/DetialAndApplyOfWWF1.html

基本WWF的研究已经有一段时间了,在Windows SDK Documentation中的有关WWF的资料也看了个差不多。现在理论上的东西基本上没有什么问题,那么问题就在于如何去应用了。从网上查了一下,这方面的案例很少,也许非WWF的其它工作流引擎的应用可能会多一些,但我没有去查。为此我自己进行了一些探索,也不知摸索的对不对,但自己感觉能够走的通,所以写下此文。可能会存在一些弯路,还望有识之士给以点评。这里以顺序工作流进行说明。

首选是持久化与锁定问题及DelayActivity过期执行的问题:

借助于WWF提供的设计器我们可以轻松的设计出一个工作流,并使之能够运行。如果活动由同一个进程来参与这是没有问题的,但工作流可能需要多个人的参与,这就需要将工作流进行持久化了。持久化要考虑的事情很多,如持久化的存储,锁定,及对DelayActivity的影响等等。

WWF提供了WorkflowPersistenceServiceSqlWorkflowPersistenceService两个类来实现持久化。但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字段的值设为最大值,即永远都不会再次被加载,当然也不会消除所占用的空间,这种情况发生的概率很小(这是我偶然发现的,当工作流实例完成,但还没有进行清除时便结束工作流的运行就会发生这样的情况!)。

(二)

原文出处:http://morepaper.cn/html/Program/20070503/4941.html

上一篇中我着重讲了有关工作流持久化的一些相关问题,这篇文章我将讲述活动执行的完整性。及如何设计我们的应用程序界面。

  我们的大多数业务数据一般都是用数据库来存储的。想象一下我们在某一个活动中对数据库中的多条数据进行操作,这些数据可能会对下一个活动产生影响;但如果此时活动执行发生意外,我们如何使业务数据和工作流的状态保持一致性?

这里面有几种方面可以使用。

  一、将工作流状态数据和业务数据使用同一个数据库,这样就可以在同一个连接中启动事务。这是一个不好的选择,我们很可能需要分离的数据库。且我们的代码必须明确启用事务和SQL语句处理。它所带来的另一个问题是我们无法实现分布式设计,这一点很糟糕。

  二、在工作流设计中使用TransactionScope。这是一个不错的选择,不过这个东西应该给是给编辑人员用的,而不是最终用户。如果让客户自己去设计工作流,工作人员则需经过一定时间的培训才会使用这种玩意:)。

  三、这可能是编程人员最喜欢用的方法,自己去实现IPendingWork接口,用于把对业务数据的处理进行封装,这些业务数据的处理可能来自远程的Web Service。同时我们还需要在引擎中启动WorkflowCommitWorkBatchService服务。 在看SDK文档时我差一点将此处忽略,然而为了数据的完整性,这是至关重要的事情。

我所关心的工作流的另一个重要的事情是:工作流如何影响我们的开发模式,我们如何组织用户界面?这里面的灵活性很高,也没有一个统一的认识,但我却感觉到了这种对传统编程方式的改变。这里我只是讲一下我自己的认识,不枉下结论,还望共同讨论。

根据项目的进展情况可以划分出两种应用。

  一、对业务数据的处理已经比较完善,这种情况为了充分利用已有的代码资源,这是的工作流的重点部分在于组织这些业务数据的处理流程。可能用到诸如CodeActivity, ListenAction, CallExternalMethod等活动。这个流程图是开发公司为用户进行定制的,用户无法去自定义这个工作流!

  二、要想让用户完全能够自定义工作流程,则给用户看到的必须是自定义的活动,这样用户才能容易将自定义活动和业务活动相联系起来。这样做的一个技术问题就是需要将工作流设计器搬到应用程序中来。至于如何实现请看下面的资源链接。

  这里我对于第二种情况进行一下详细的说明。在工作流应用之前,我的应用程序在界面上的布局主要是以数据为核心进行布局的;多个人可能在同一堆数据依据权限和固化的流程进行操作。而引入工作流后,因为流程是不固定的,这就对以前的应用模式构成了挑战:应用程序不关心下一个操作是什么(由引擎导向),只有一种提交与否的状态选择。也就是说一个工作人员不需要从界面中选择合适的数据并明确地指出将把数据置入一个什么样的处理流程中。情况变得好像简单多了,他可以直接看到他要处理的数据,并做出处理结果便可以了。

  由于引入工作流后,每个工作人员的操作模式被统一起来:进入应用程序后直接显示要处理的数据,做完处理后提交。所以我们有理由将用户的这种界面进行统一起来,我们只关心业务数据的处理,而不关心业务数据的流程!为此我们在自定义活动中加入一个人员列表,这样用户管理员在工作流自定义时便可指定可对该活动进行操作的人员列表。每个工作人员在登录后只列出能够操作的活动列表。选择一个活动便可进入工作状态。这样的感觉很好。

  为了实现这样的功能我们还要做一些文章,工作人员为了进行处理,还需要和工作流进行交互,这里我们需要一个EventDriven吗?,如果用的话我们的自定义活动将变得很复杂,或者根本就不能用;如果不用的话,工作人员如何告诉工作流处理的结果呢(应用程序和工作流实例工作于两个独立的线程中)。有一种方法那就是用ManualWorkflowSchedulerService服务,这样可以使工作流引擎和应用程序位于同一线程之内运行。或许有更好的法子,请不要忘记告诉我。

  还有件事情得做,给每一个自定义活动打上一个PersistOnCloseAttribute属性。很重要,我们需要有一个机会让工作流停下来,PersistOnCloseAttribute是一个不错的选择。

  用户中的管理员可能经常改变流程处理,做一个版本记录吧,不要直接修改已经运行着的工作流实例!(不是不能修改运行的工作流实例,但不建议这样做)。这样已经运行的用老的版本,对于新建的工作流用新的工作流设计。两者都运行的很好,何乐而不为呢。

差不多了,先写这些吧。希望对大家有帮助。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: