工作流中活动状态管理与重试机制

在复杂的工作流管理中,经常会遇到需要调用外部或内部Web服务的情况。如果这些服务因为内部服务器错误而抛出异常,可能会导致整个工作流的终止。本文将介绍一种解决方案,即使在活动失败的情况下,也能够重新执行活动,而不是让整个工作流终止。

在项目开发过程中,经常会遇到需要调用外部或内部Web服务的情况。如果这些服务因为内部服务器错误而抛出异常,可能会导致整个工作流的终止。为了解决这个问题,需要实现一种机制,使得在活动失败时能够重新执行该活动,而不是让整个工作流终止。

活动状态的理解

工作流中,一个活动在其生命周期内可能会经历以下几种状态:初始化(Initialized)、执行(Executing)、取消(Canceling)、关闭(Closed)、补偿(Compensating)和故障(Faulting)。

Initialized状态下,为活动创建了ActivityExecutionContext,并执行了特定于该活动的初始化细节。当活动进入Executing状态时,执行该活动的主要功能。如果父活动明确地将活动置于Canceling状态,或者在执行该活动时抛出异常,则活动将进入Canceling状态。Closed状态是活动的最后一个状态。

如果活动成功完成,但根据业务逻辑需要进入补偿状态,那么活动将从Closed状态过渡到Compensating状态,然后一旦补偿逻辑完成,再回到Closed状态。

研究重点

知道,如果在活动的Executing状态、Canceling状态或Compensating状态中抛出异常,它将过渡到Faulting状态。

注意:一旦活动进入Closed状态,它就不能移动到Executing状态。由于知道一旦活动关闭,它就不能移动到执行状态,但可以重新执行活动,然后它关闭。这意味着如果活动由于任何原因进入Faulting状态,它可以返回到Executing状态。

实现从故障状态到执行状态的转换

可以通过处理活动内部的故障来实现这一点。通过覆盖HandleFault方法,可以知道什么是执行上下文以及抛出了什么类型的异常,并且可以通过调用Execute方法来重新执行活动,传递执行上下文。但必须非常小心地做这件事,并且应该确保正在正确地处理重试逻辑,因为如果不这样做,可能会导致死锁。

代码实现

在这里,将向展示示例POC项目是如何实现的,也可以使用相同的方法来实现它。

唯一不同的是重试逻辑/需求。总是需要确保重试逻辑不会进入无限循环。

项目解决方案

在这个项目中,有一个顺序工作流,包含三个活动。在CallWebServices活动中,试图模拟这个活动正在调用Web服务,并且可能会得到服务器错误,这将引发服务器错误故障异常,导致整个工作流终止。

现在,为了解决整个工作流终止的问题,并再次执行同一个活动,以便如果下一次重试成功并且从Web服务获得成功的响应,工作流应该继续完成编排。

重试机制

为了实现这个问题的解决方案,添加了一个BaseActivity,它将被所有的工作流活动继承。

还为基活动添加了一个依赖属性,以设置/限制重试次数。因此,任何继承基活动的活动都应该设置这个属性。在下面的图片中,将AllowedReplayCount设置为CallWebServices活动为2,这意味着这个活动最多可以重试2次。

public static DependencyProperty AllowedReplayCountProperty = DependencyProperty.Register( "AllowedReplayCount", typeof(Int32), typeof(MyBaseActivity)); [DescriptionAttribute("AllowedReplayCount")] [CategoryAttribute("Replay Category")] [BrowsableAttribute(true)] [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)] public Int32 AllowedReplayCount { get { return ((Int32)(base.GetValue(MyBaseActivity.AllowedReplayCountProperty))); } set { base.SetValue(MyBaseActivity.AllowedReplayCountProperty, value); } }

在这个基活动中,通过覆盖HandleFault函数来处理活动抛出的故障。这个函数给提供了两个重要的数据:执行上下文和异常。使用这些数据,应用了重试逻辑。

protected override ActivityExecutionStatus HandleFault(ActivityExecutionContext executionContext, Exception exception) { if (exception is WebException && ReplayCount < AllowedReplayCount) { if (!exception.Message.Contains("404") || !exception.Message.Contains("409")) { Console.WriteLine("Faulted " + executionContext.Activity.Name); ReplayCount++; return Execute(executionContext); } } return base.HandleFault(executionContext, exception); }

到目前为止,已经看到了如何通过执行HandleFault函数来重试同一个活动,但这还不是全部,还需要工作流在重试成功之后执行其他活动。这是因为它的基本特性是,如果任何活动出现故障,它将终止整个工作流。所以需要阻止工作流从执行状态进入故障状态。

为了实现这种情况,在基活动中添加了faultHandlerAcitivity。为了支持重试,将faultHandlerActivity的故障类型设置为System.Net.WebException。此外,还添加了codeActivity

private void codeActivity1_ExecuteCode(object sender, EventArgs e) { CodeActivity senderActity = sender as CodeActivity; FaultHandlerActivity faultException = senderActity.Parent as FaultHandlerActivity; if (faultException.Fault is WebException) { if (ReplayCount > AllowedReplayCount) { throw faultException.Fault; } } else { throw faultException.Fault; } }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485