【问题标题】:Exception escapes from workflow despite TryCatch activity尽管有 TryCatch 活动,异常从工作流中逃逸
【发布时间】:2010-09-22 18:39:19
【问题描述】:

我在 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(尽管这显然是一个未处理的异常)。

EDIT 2:我启用了调试日志,这提供了一些额外的见解。 “自定义数据库活动”成功运行完成。指示出现问题的第一个事件日志条目是详细级别消息:运行时事务已完成,状态为“已中止”。接下来我看到一条信息消息:WorkflowInstance Id: 'dbd1ba5c-2d8a-428c-970d-21215d7e06d9' E2E Activity(不确定这是什么意思)。之后的信息消息是:Activity 'System.Activities.Statements.TransactionScope', DisplayName: 'Transaction for run immediate checks', InstanceId: '389' has completed in the 'Faulted' state

在此消息之后,我看到每个父级(包括 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 类。

【问题讨论】:

  • 只是一个猜测,但也许您需要捕获TransactionException,而不是Exception
  • 我会尝试添加更多具有更具体异常类型的捕获,但我希望捕获通用 Exception 将处理所有异常..
  • 添加更具体的 catch 语句不起作用。我得到相同的结果:工作流中止。
  • 您在使用 SqlWorkflowInstanceStore 吗?它使用的是同一个数据库吗?
  • 我没有为此工作流配置InstanceStore,因此它不会被持久化。我通过启用调试日志找到了一些额外的信息。我会把这个添加到问题中。

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


【解决方案1】:

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

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

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

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

设计假设是,一旦事务中止,事务中获取的任何状态都无法安全使用 - 因为事务中止,所有状态都将被丢弃。

【讨论】:

  • 有趣。但是,我不相信这是实际问题。在事务中止之前,我实际上没有看到我的 TryCatch 活动关闭。但是,我再次查看了 TransactionScope 活动完成时会发生什么。它似乎在排队 CompleteTransactionWorkItem。这表明正在进行异步操作。但是,这也一定意味着在某个时间点,工作流线程和事务线程加入,将我发布的堆栈跟踪返回给我。我没有看到这种情况发生在任何地方(我什至找不到另一个线程使工作项出队)。
  • 实际上,一旦事务失败,工作流就会立即终止(这就是 try/catch 不关闭的原因)。如果您能够在事务中止时调用工作流中的代码,您可能会无意中对在失败的事务下创建的状态执行某些操作。这违反了事务的隔离语义,因此是不允许的。
  • 好的,我明白了。但是,TryCatch 实际上并没有捕捉到我预期会被捕捉到的东西,这似乎有点违反直觉。因此,在工作流中使用TransactionScope 时,您必须仔细考虑您希望事务中止时的行为。我可能应该去看看更多 Endpoint.tv 节目:)
【解决方案2】:

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

【讨论】:

  • 我知道这解决了我的问题,但它似乎有点解决方法......而且我仍然没有明确的答案来解释为什么 TryCatch 没有捕捉到这个特定的异常。罗恩的答案正确吗?我的TryCatch 没有捕捉到事务尝试完成时生成的异常的原因是异步发生的吗?
  • Ron 知道他的事务编码。所以这不是一种解决方法,这就是它的设计方式。我必须承认并不完全符合我的预期或非常直观,但使用 SqlWorkflowInstanceStore 是 WF4 中错误处理/重试的一种正常方式。
猜你喜欢
  • 1970-01-01
  • 2015-06-10
  • 2017-06-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多