抑制NServicebus Transaction将错误写入数据库

时间:2011-08-20 09:06:22

标签: nhibernate nservicebus transactionscope

我正在使用NServiceBus来处理一些计算消息。我有一个新的要求,通过编写相同的数据库来处理计算错误。我正在使用NHibernate作为我的DAL,它自动登记到NServiceBus事务并在异常情况下提供回滚,这非常有效。但是,如果我将此特定错误写入数据库,它也会回滚,这是一个问题。

我知道这将是一个问题,但我想我可以使用TransactionScopeOption = Suppress将调用包装在一个新事务中。但是,错误数据仍然会回滚。我相信那是因为它使用现有的会话已经登记在NServiceBus交易中。

接下来,我尝试从抑制事务范围内的现有SessionFactory中打开一个新会话。但是,第一次调用数据库以使用此新会话阻止检索或保存数据,然后超时。

  

InnerException:System.Data.SqlClient.SqlException         消息=超时已过期。在完成>操作之前经过了超时时间,或者服务器没有响应。

最后,我尝试使用它创建一个新的SessionFactory,以在禁止事务范围内打开一个新会话。然而,它再次阻止和超时。

我觉得我在这里遗漏了一些明显的东西,并且非常感谢有关这个可能是共同任务的任何建议。

2 个答案:

答案 0 :(得分:1)

正如Adam在评论中所建议的那样,在大多数情况下,最好让整个消息失败处理,使内置的重试机制有机会使其正确,并最终进入错误队列。然后,另一个进程可以监视错误队列并执行任何所需的通知,包括记录到数据库。

但是,有一些使用情况,整个消息不是失败的,即总的来说,它“成功”(无论是依赖于业务的定义),但有一些小部分是错误的。例如,一种财务计算,其中处理“成功”但数据的某些人为因素是“错误的”。在这种情况下,我建议捕获该异常并发送一条新消息,当该消息由另一个端点处理时,会将该信息记录到您的数据库中。

我可以看到另一种情况,你希望整个消息失败,但是你想要以某种方式尝试注意它的事实。这可能与您描述的最接近。在这种情况下,使用TransactionScopeOption = Suppress创建一个新的TransactionScope,然后(再次)在该范围内发送一条新消息。无论您的完整邮件交易是否回滚,都会发送该邮件。

您的事务正在回滚是正确的,因为NHibernate会话在事务生效时打开。尝试在被抑制的事务中打开新会话可能会导致锁定问题。这就是为什么,在大多数情况下,异步发送新消息是这些情况下解决方案的一部分,但是你如何做到这一点取决于你的具体业务需求。

答案 1 :(得分:0)

我知道我迟到了,但作为一个替代建议,你只需要提出另一个单独的日志消息,NSB独立处理,例如:

public void Handle(DebitAccountMessage message)
{
    var account = this.dbcontext.GetById(message.Id);
    if (account.Balance <= 0)
    {
        // log request - new handler
        this.Bus.Send(new DebitAccountLogMessage
            {
                originalMessage = message,
                account = account,
                timeStamp = DateTime.UtcNow
            });

        // throw error - NSB will handle
        throw new DebitException("Not enough funds");
    }
}

public void Handle(DebitAccountLogMessage message)
{
    var messageString = message.originalMessage.Dump();
    var accountString = message.account.Dump(DumpOptions.SuppressSecurityTokens);
    this.Logger.Log(message.UniqueId, string.Format("{0}, {1}", messageString, accountString);
}