[译者按]Andy Li这篇文章,是我看过的最好的,最透彻的关于SharePoint Workflow架构的文章。通过阅读他的文章,我才清楚的了解了SharePoint Workflow的运作机制,并且在遇到问题的时候,知道如何下手查找问题。因此翻译过来,希望对Workflow的开发人员有帮助。
这篇博客是由Andy Li贡献的,他是SharePoint开发人员支持组的处理疑难问题的工程师。原文地址。这个关于Workflow的系列,是他贡献给社区的,帮助大家更好的理解Workflow运行时的内部机制,以及如何和SharePoint交互。
这篇文章由SPFarmer翻译。
前三篇地址:
宿主服务(HostService):
SPWinOeHostService
SharePoint
和Workflow Runtime的结合
Workflow 事件处理管道(Event Processing Pipeline)
High Level Event Processing
大多数workflow都是事件驱动型的workflow。当workflow到达特定的需要从外部输入的Activities,workflow
runtime就会调用SharePoint持久化服务,把workflow实例的数据保存到内容数据库里。下面的数据流图表简要的描述了SharePoint
workflow是如何响应外部的event的。
1. Eventreceiver 响应用户操作
就像我们之前说的,
有几种 workflow event receivers
可以响应用户操作. SPWinOEItemEventReceiver
响应 task
和 list item
事件, 比如 ItemUpdated andItemDeleted. 这些事件包含如下信息:
- 和这个事件关联的task
或者 list item.
- 有改动的Task或者List item的BeforeProperties
和 AfterProperties.
- 事件类型,
可以是 ItemAdded, ItemUpdated, ItemDeleted orSharePoint event receiver处理的任何类型的事件.
Event receiver 发送事件数据给SPWorkflowManager.
2. En-queuing event
SPWorkflowManager会尝试运送事件给对应的workflow
实例(每一个task
都有一个“WorkflowInstanceID”属性,
这也是SharePoint
如何知道应该把事件发送给哪个workflow实例).
SPWorkflowManager在把事件传递之前,以WorkItem的形式,把事件加到内容数据库的队列里(ScheduleWorkItem表).
这个是因为,实际上,事件传递过程可能是长,并且可能失败。因此加到队列里,很简单是为了能够容错。如果传递这个事件出错,我们可以重新获取这个事件,然后重新尝试传递。 我们会介绍如何通过读取数据库来查找workflow事件传递失败的原因。
3. Delivering event
SPWorkflowManager通过把事件发送给SharePoint workflow runtime (SPWinOeHostService)来继续传输事件。宿主服务负责加载workflow实例到runtime里,并且提交事件到workflow实例里。这个时候,就会调用OnTaskChanged activity的MethodInvoked 方法。
4. Dequeuing event
如果workflow
实例成功的处理了事件,我们会在ScheduleWorkItems表里面删除这个事件,并把这个事件管道标记成结束。
Event Pipeline
为了更好的了解这些组件是如何在一起工作的,让我们看一下SharePoint处理task相关的activity的典型的情景。这个过程过程始于
workflow 运行CreateTask activity.
结束于workflow
完成CompleteTask activity.
1. CreateTask activity继承了CallExternalMethodActivity.
这个 activity是workflow instance
和SharePoint开始数据交换会话的地方。 TaskId
也是在这个时候初始化的。
2. Workflowruntime 调用SPWinOeTaskService.CreateTask来创建一个真正的task item.
记住SPListeitem只是在内存里面被创建了,并且没有被提交到数据库里。真正的提交是在workflow持久化之前,由WorkBatch
service实现的。
3. Workflow的下一个activity
是 OnTaskChanged activity。 Workflow runtime
会调用 Subscription Service,
它会在我们刚才创建的task上,建立一个用来处理ItemUpdated时间的event receiver。
4. Workflowruntime会创建一个event sink来响应OnTaskChanged 事件。
5. 现在workflow实例没有其他事情要做了,因为他在等待用户提交task。持久化服务会调用,保存workflow实例到内容数据库。记住,内存里的SPListitem也是在这个时候被提交。
6. 用户通过Task表单提交对task的修改。Task表单实际上一个apsx页面,通过调用Object
Module来更新task item. Task表单调用的是SPWorkflowTask.AlterTask() API
来提交对task的修改。这个会触发以前注册上来的event receiver的ItemUpdated事件。
NOTE: 你可能会初一到,每一个workflow task都有一个特别的field叫“WorkflowVersion”.
这个列的值,被SPWorkflowTask.AlterTask()设置成一个大一1的值(表示这个task被lock了)
,这个表示这个task上面有一个更新,并且需要相应的workflow实例来做一些action。这个同时也意味着,在被workflow实例处理之前,这个task被保持在lock状态。
问题:如果我多次调用了AlterTask() API,我收到了一个“task被loack”的异常,为什么呢?
答案: AlterTask API
内部调用了SPListItem.Update(). 如果他检测到这个task属于一个正在运行的workflow
instance, 它会把“WorkflowVersion”
列的值设置成一个大于1的值。现在如果你尝试再次调用SPListItem.Update() ,
他会检测 “WorkflowVersion”这个列,如果他的值大于1,
我们停止更新,并且抛出这个异常。通过这种方式,我们在workflow处理完OnTaskChange事件之前,阻止对于item的任何修改。 只有在OnTaskChanged activity
被workflow实例处理完之后, “WorkflowVersion”
会被设置成1,表示这个task被解锁(unlock)了。
7. 现在我们继续。Event receiver
会响应SPListItem.Update()并且通过调用SPWorkflowManager.RunWorkflow尝试把事件传输给workflow
runtime。
8.SPWorkflowManager 生成一个 WorkItem 并且把它放到数据库里(enqueuing, ScheduledWorkItems
表). WorkItem记录的是,在workflow实例处理之前的,处于pending状态的task的ItemUpdate事件。我们保存这个事件在内容数据库里是为了容错处理。如果因为任何原因,这个事件没有传递成功,workflow的timer
job可以从数据库里找到这个WorkItem,并且继续处理他。
9.SPWorkflowManager 继续传输这个事件到SharePoint workflow runtime(SPWinOeHostService). SPWinOeHostService
检查这个事件,并且从这个事件获取两个数据: WorkflowInstanceID 和TaskID. It
加载workflow实例到 workflow runtime. 并且提交OnTaskChanged 事件到
workflow 实例,你的OnTaskChanged.OnInvoked() 里面的自定义代码在这个时期被调用。
问题:TaskId存储在哪里?
答案:每一个workflow task都有一个列叫做“GUID”,
这个就是 TaskID.
10. workflowruntime 执行完 OnTaskChanged activity之后,
他把 WorkItem 从数据库里面删掉。Task的 “WorkflowVersion”
列会被设置成 “1” (unlocked)
然后 event receiver is deleted from the tasklist.
关于Workflow Timer Jobs
我们曾经说过,当SPWorkflowManager
尝试去传送事件到宿主服务(SPWinOEHostService),
他需要检查几个条件。 其中的一个条件是确认workflow
没有锁住并且没有在其他地方运行。一个SharePoint场环境,可以有多个前端服务器(web frontend servers)。workflow
runtime可以寄宿在其中的任何一个server。我们需要确保workflow instance在任何时间内,只被其中的一个workflow
runtime 处理。SharePoint的机制是在数据库里设置一个flag,来标识锁定状态。SPWorkflowManager可以简单的查出workflow
是否被锁定。如果这个workflow被锁定了, SPWorkflowManager
会把 WorkItem
放到数据库的队列里,timer job
会异步处理这个事件。
Workflow timerjob 负责处理队列里的WorkItems.
这种情况下timer service就是 workflow runtime的宿主。这里有3个和workflow
相关的timer job
,它们处理不同的作业。下面的表格列出了它们的主要的功能:
Job |
Description |
SPWorkflowFailOverJobDefinition |
一个workflow可能因为多种原因失败。如果他在中途失败,他会被锁定并且不能够重新启动。Fail-over timer job 的作用是解锁这些workflow,使它们能继续运行。 |
SPWorkflowJobDefinition |
处理ScheduleWorkItem 队列里的WorkItems. w3wp.exe 总是尝试在第一时间传输事件到workflow。但是如果workflow被别的进程锁住了,它会把事件放到数据库队列里。默认情况下,这个 timer job 会处理这些事件。 |
SPWorkflowAutoCleanJobDefinition |
清楚数据库里的旧的workflow instances。默认情况下,这个job会清楚60天之前完成的workflows。你可以通过修改SPWorkflowAssociation.AutoCleanupDays属性来设置默认值 。 |
每五分钟,SPWorkflowJobDefinition被唤醒并且在数据库里查找 WorkItems
。数据库里的WorkItem记录包含了所有pending状态的工作。比如workflow instance
ID, task item ID, event type等等。对于每一个WorkItems, timer job通过WorkItem记录重新组装
SPWorkflowEvents对象。他调用SPWorkflowManager.RunWorkflow() 并且把事件传递给Workflow实例。
未完待续。