Nhibernate NServiceBus正在重试消息,即使没有异常

Nhibernate NServiceBus正在重试消息,即使没有异常,nhibernate,nservicebus,nservicebus3,Nhibernate,Nservicebus,Nservicebus3,我遇到了一个wierd问题,NServiceBus多次转发消息X,尽管处理程序中没有抛出异常。有一些关于NHibernate会话和NSB环境事务的信息。由于没有抛出错误,我对问题不是100%确定,因此无法真正决定要做什么 我让国家安全局配置了温莎城堡,就像这样: IWindsorContainer container = new WindsorContainer(new XmlInterpreter()); container.Install(new ContainerInstaller());

我遇到了一个wierd问题,NServiceBus多次转发消息X,尽管处理程序中没有抛出异常。有一些关于NHibernate会话和NSB环境事务的信息。由于没有抛出错误,我对问题不是100%确定,因此无法真正决定要做什么

我让国家安全局配置了温莎城堡,就像这样:

IWindsorContainer container = new WindsorContainer(new XmlInterpreter());
container.Install(new ContainerInstaller());
container.Install(new UnitOfWorkInstaller(AppDomain.CurrentDomain.BaseDirectory, Castle.Core.LifestyleType.Scoped));
container.Install(new FactoryInstaller(AppDomain.CurrentDomain.BaseDirectory));
container.Install(new RepositoryInstaller(AppDomain.CurrentDomain.BaseDirectory));

Configure.With()
    .CastleWindsorBuilder(container)
    .FileShareDataBus(Properties.Settings.Default.DataBusFileSharePath)
    .MsmqTransport()
        .IsTransactional(true)
        .PurgeOnStartup(false)
    .UnicastBus()
         .LoadMessageHandlers()
         .ImpersonateSender(false)
     .JsonSerializer();
UnitOfWorkInstaller
注册工作单元(NHibernate会话),如下所示:

我的处理程序的结构如下:(unitOfWork作为构造函数依赖项传递)

公共无效句柄(消息)
{
使用(_unitOfWork)
{
尝试
{
//做事
_unitOfWork.Commit();
}
捕获(例外情况除外)
{
_unitOfWork.Rollback();
//重新播放,使消息留在队列中
投
}
}
}
我发现,如果我不提交工作单元(刷新会话并提交事务),我会收到一个错误,说消息重试次数超过了最大重试次数bla bla bla bla bla

因此,它似乎与NHibernate会话及其创建和处理方式有关,但由于它是在工作单元内创建的,因此我不能真正使用会话工厂。我读到我可以使用IMessageModule来创建和处理会话,但我也不知道这是否是正确的方法,因为我不知道是什么原因首先导致了错误

因此,总结一下:

  • 我正在使用一个有范围的工作单元,这样所有使用它的处理程序依赖项都将共享同一个实例(对于子容器,顺便说一句:我将工作单元设置为瞬态,认为子容器将把该容器中的所有瞬态对象视为单个对象,但我看到工作单元没有共享,因此将其设置为作用域)

  • 我将处理程序包装在
    中,使用(_unitOfWork){}
    语句在每次处理后处理工作单元

  • 当处理工作单元时,也会处理NHibernate会话

  • 如果我没有在
    \u unitOfWork
    上显式调用
    Commit
    ,消息重试次数将超过最大重试次数,然后抛出错误


是什么导致了这种行为?IMessageModule就是这个问题的答案吗?

我想我把它缩小了一点…我使用(\u unitOfWork)删除了所有的
,使用
\u unitOfWork.Commit()
\u unitOfWork.Rollback()
并让NSB
TransactionScope
执行提交或回滚事务的工作,因为NHibernate的会话登记在NSB事务范围内

我还开始使用NHibernate会话的事务(
session.transaction
),而不是通过
session.BeginTransaction()
获取对它的引用并使用此事务。我复制/粘贴了我的UoW实现,以便您可以看到差异(旧代码在注释中)

我不知道我的更改除了使用会话的事务和删除刷新之外是否还有其他原因,因为它在事务提交中处理似乎已经解决了问题…我不必显式调用
commit
方法来成功处理消息修订:

public class NHibernateUnitOfWork : INHibernateUnitOfWork
{
    //private ITransaction _transaction;
    private bool _isDisposed;
    private bool _isInError;

    public ISession Session { get; protected set; }

    public NHibernateUnitOfWork(ISession session)
    {
        Contract.Requires(session != null, "session");
        Session = session;

        //_transaction = Session.BeginTransaction();

        // create a new transaction as soon as the session is available
        Session.BeginTransaction();
        _isDisposed = false;
        _isInError = false;
    }

    public void MarkCreated(Object entity)
    {
        // assert stuff

        try
        {
            Session.SaveOrUpdate(entity);
            //Session.Flush();
        }
        catch (HibernateException ex)
        {
            HandleError();
            throw;
        }
    }

    public void MarkUpdated(Object entity)
    {
        // assert stuff

        try
        {
            Session.Update(entity);
            //Session.Flush();
        }
        catch (HibernateException ex)
        {
            HandleError();
            throw;
        }
    }

    public void MarkSavedOrUpdated(Object entity)
    {
        // assert stuff

        try
        {
            Session.SaveOrUpdate(entity);
            //Session.Flush();
        }
        catch (HibernateException)
        {
            HandleError();
            throw;
        }
    }

    public void MarkDeleted(Object entity)
    {
        // assert stuff

        try
        {
            Session.Delete(entity);
            //Session.Flush();
        }
        catch (HibernateException ex)
        {
            HandleError();
            throw;
        }
    }

    public void Commit()
    {
        // assert stuff

        try
        {
            //Session.Flush();
            //_transaction.Commit();
            Session.Transaction.Commit();
        }
        catch (HibernateException ex)
        {
            HandleError();
            throw;
        }
    }

    public void Rollback()
    {
        // assert stuff

        try
        {
            //if (!_transaction.WasRolledBack)
            //{
            //    _transaction.Rollback();
            //}
            Session.Transaction.Rollback();
        }
        catch (HibernateException ex)
        {
            HandleError();
            throw;
        }
    }

    public void Dispose()
    {
        if (!_isDisposed)
        {
            DiscardSession();
            _isDisposed = true;
        }
    }

    private void DiscardSession()
    {
        //if (_transaction != null && _transaction.IsActive)
        //{
        //    _transaction.Dispose();
        //}
        if (Session != null)
        {
            try
            {
                // rollback all uncommitted changes
                if (Session.Transaction != null && Session.Transaction.IsActive)
                {
                    Session.Transaction.Rollback();
                }
                //Session.Clear();
                Session.Close();
            }
            catch (Exception)
            { }
            finally
            {
                Session.Dispose();
            }
        }
    }

    private void HandleError()
    {
        _isInError = true;
        //if (_transaction != null && _transaction.IsActive)
        //{
        //    _transaction.Rollback();
        //}
        if (Session.Transaction != null && Session.Transaction.IsActive)
        {
            Session.Transaction.Rollback();
        }
    }

    // assert methods
}

所有这些都有意义吗?我仍然不知道首先是什么导致了错误,但似乎与在事务作用域完成之前处理NHibernate会话有关。

查看错误队列中的消息。消息头中是否有异常消息?@stephenl No,我看到的唯一一样带有
的消息。它似乎与NHibernate相关,但我没有任何NSB与NHibernate的集成。我只是注意到,只有当UoW设置为瞬态时,它才起作用。如果它设置为作用域,则不起作用。我认为Castle Windsor支持子容器,但它似乎不起作用……如果我的处理程序有2个dep相关性,一个是UoW本身,另一个是对UoW也有依赖关系的存储库,它们将不同。
    public void Dispose()
    {
        if (!_isDisposed)
        {
            DiscardSession();
            _isDisposed = true;
        }
    }

    private void DiscardSession()
    {
        if (_transaction != null && _transaction.IsActive)
        {
            _transaction.Dispose();
        }
        if (Session != null)
        {
            Session.Dispose();
        }
    }
    public void Handle(<MessageType> message)
    {
        using (_unitOfWork)
        {
            try
            {
                // do stuff
                _unitOfWork.Commit();
            }
            catch (Exception ex)
            {
                _unitOfWork.Rollback();

                // rethrow so the message stays in the queue
                throw;
            }
        }
    }
public class NHibernateUnitOfWork : INHibernateUnitOfWork
{
    //private ITransaction _transaction;
    private bool _isDisposed;
    private bool _isInError;

    public ISession Session { get; protected set; }

    public NHibernateUnitOfWork(ISession session)
    {
        Contract.Requires(session != null, "session");
        Session = session;

        //_transaction = Session.BeginTransaction();

        // create a new transaction as soon as the session is available
        Session.BeginTransaction();
        _isDisposed = false;
        _isInError = false;
    }

    public void MarkCreated(Object entity)
    {
        // assert stuff

        try
        {
            Session.SaveOrUpdate(entity);
            //Session.Flush();
        }
        catch (HibernateException ex)
        {
            HandleError();
            throw;
        }
    }

    public void MarkUpdated(Object entity)
    {
        // assert stuff

        try
        {
            Session.Update(entity);
            //Session.Flush();
        }
        catch (HibernateException ex)
        {
            HandleError();
            throw;
        }
    }

    public void MarkSavedOrUpdated(Object entity)
    {
        // assert stuff

        try
        {
            Session.SaveOrUpdate(entity);
            //Session.Flush();
        }
        catch (HibernateException)
        {
            HandleError();
            throw;
        }
    }

    public void MarkDeleted(Object entity)
    {
        // assert stuff

        try
        {
            Session.Delete(entity);
            //Session.Flush();
        }
        catch (HibernateException ex)
        {
            HandleError();
            throw;
        }
    }

    public void Commit()
    {
        // assert stuff

        try
        {
            //Session.Flush();
            //_transaction.Commit();
            Session.Transaction.Commit();
        }
        catch (HibernateException ex)
        {
            HandleError();
            throw;
        }
    }

    public void Rollback()
    {
        // assert stuff

        try
        {
            //if (!_transaction.WasRolledBack)
            //{
            //    _transaction.Rollback();
            //}
            Session.Transaction.Rollback();
        }
        catch (HibernateException ex)
        {
            HandleError();
            throw;
        }
    }

    public void Dispose()
    {
        if (!_isDisposed)
        {
            DiscardSession();
            _isDisposed = true;
        }
    }

    private void DiscardSession()
    {
        //if (_transaction != null && _transaction.IsActive)
        //{
        //    _transaction.Dispose();
        //}
        if (Session != null)
        {
            try
            {
                // rollback all uncommitted changes
                if (Session.Transaction != null && Session.Transaction.IsActive)
                {
                    Session.Transaction.Rollback();
                }
                //Session.Clear();
                Session.Close();
            }
            catch (Exception)
            { }
            finally
            {
                Session.Dispose();
            }
        }
    }

    private void HandleError()
    {
        _isInError = true;
        //if (_transaction != null && _transaction.IsActive)
        //{
        //    _transaction.Rollback();
        //}
        if (Session.Transaction != null && Session.Transaction.IsActive)
        {
            Session.Transaction.Rollback();
        }
    }

    // assert methods
}