尽管有TryCatch活动,但异常会从工作流中逃脱

时间:2010-09-22 18:39:20

标签: c# transactions .net-4.0 workflow-foundation workflow-foundation-4

我在Windows服务中有一个工作流,它是一个定期执行工作的循环。这项工作是在TryCatch活动中完成的。 Try属性是TransactionScope活动,它包含一些读取和更新数据库的自定义活动。当事务失败时,我会指望任何导致此事件被TryCatch捕获的异常。但是,我的工作流程中止了。我的工作流程如下:

var wf = new While(true)
{
    Body = new Sequence
    {
        Activities =
        {
            new TryCatch
            {
                Try = new TransactionScope
                {
                    IsolationLevel = IsolationLevel.ReadCommitted,
                    Body = new Sequence
                    {
                        Activities = { ..custom database activities.. }
                    },
                    AbortInstanceOnTransactionFailure = false
                },
                Catches =
                {
                    new Catch<Exception>
                    {
                        Action = new ActivityAction<Exception>
                        {
                            Argument = exception,
                            Handler = ..log error..
                        }
                    }
                }
            },
            new Delay { Duration = new InArgument<TimeSpan>(duration) }
        }
    },
}

在我的情况下,数据库有时可能不可用,因此显然事务不会提交。在这种情况下会发生的情况是工作流程中止,但有以下异常:

  

System.OperationCanceledException:处理当前工作项的错误导致工作流中止。

内部例外是:

  

System.Transactions.TransactionException:该操作对事务状态无效。

这很有意义,因为我刚刚关闭了数据库。但是,为什么我的TryCatch活动不会处理此异常?

编辑1 :一些其他信息。我使用WorkflowApplication类运行工作流程。为了更好地了解发生了什么,我指定了属性AbortedOnUnhandledException。发生异常时,它会直接转到Aborted并跳过OnUnhandledException(尽管这显然是未处理的异常)。

编辑2 :我启用了调试日志,这提供了一些额外的见解。 “自定义数据库活动”成功运行完成。指示出现错误的第一个事件日志条目是详细级别消息:运行时事务已完成,状态为“已中止”。接下来我看到一条信息消息: WorkflowInstance Id:'dbd1ba5c-2d8a-428c-970d-21215d7e06d9'EME活动(不确定这意味着什么)。之后的信息消息是:活动'System.Activities.Statements.TransactionScope',DisplayName:'立即运行的事务检查',InstanceId:'389'已在'故障'状态中完成。

在此消息之后,我看到每个父母(包括TryCatch活动)都处于“故障”状态,最后是我的工作流程中止。

编辑3 :要清楚,当任何“自定义数据库活动”发生异常时,一切都按预期工作。捕获异常并继续工作流程。当事务无法在TransactionScope结束时提交时,它才会出错。请参阅从Aborted回调记录的以下堆栈跟踪:

at System.Transactions.TransactionStateInDoubt.Rollback(InternalTransaction tx, Exception e)
at System.Transactions.Transaction.Rollback(Exception e)
at System.Activities.Runtime.ActivityExecutor.CompleteTransactionWorkItem.HandleException(Exception exception)

如果您按照TransactionScope.OnCompletion(...)的来电,最终您将从堆栈跟踪到达ActivityExecutor类。

2 个答案:

答案 0 :(得分:5)

事务以异步方式提交事务。由于资源管理器级别存在问题,您无法对提交事务的失败作出反应。

正如您所指出的,您可以处理活动中发生的异常。如果您查看工作流程的跟踪记录,我猜您会在事务中止之前看到TryCatch活动已关闭。

许多年前,当我担任COM +团队的项目经理时,我研究了这个问题,因为通常人们想要一个事务组件(或工作流),就像在这种情况下能够对事务中止做出反应。

事务解析的异步性质意味着您无法在组件本身中对其做出反应。解决方案是在调用者中做出反应,然后可以采取一些行动。

设计假设是,一旦事务中止,就不能安全地使用事务中的状态 - 它将全部被丢弃,因为事务被中止。

答案 1 :(得分:2)

只是为了补充罗恩的答案。这里唯一的选择是添加SqlWorkflowInstanceStore并在TransactionScope之前删除一个Persist活动。当事务中止时,整个工作流将中止,但过去保存的状态仍将在持久性数据库中,并且可以从此先前保存的状态重新启动工作流并再次执行事务。