由Bus.Publish()或订阅引起的StackOverflowException?

时间:2012-01-09 06:26:14

标签: c# msmq nservicebus saga

我有一个代理人使用传奇来跟踪给定类型的传入消息,直到收到超时消息。在Timeout处理程序中,我有以下内容:

public override void Timeout(object state)
        {
            // If Data.IsNull: Do nothing!!! Report to log only.
            Logger.Debug("=========================================================================");
            Logger.Debug(string.Format("Timeout message received. State: {0}.", state.ToString()));

            QuickBatch qbBuilder = new QuickBatch();
            // Create new message and publish it
            BankRequestBatchClosed eventMessage = Bus.CreateInstance<BankRequestBatchClosed>();

            eventMessage.UniqueBatchIdentifier = qbBuilder.GenerateUniqueBatchIdentifier(QuickBatch.QB_BATCHTYPE_CC);
            eventMessage.ScheduleBatchID = this.Data.ScheduleBatchID;
            eventMessage.EventDate = DateTime.Now;
            eventMessage.EventID = Guid.NewGuid();
            eventMessage.TransactionItems = this.Data.PaymentRequestedTransactionItems;

            Logger.Debug("=========================================================================");
            Logger.Debug(string.Format("Timeout method about to send BankRequestBatchClosed message. UniqueBatchIdentifier: {0}",eventMessage.UniqueBatchIdentifier));

            Bus.Publish(eventMessage);
            Complete();
        }

TransactionItems是ICollection

这是TransactionDetail类:

   [Serializable]
    public class TransactionDetail
    {
        // Guid needed for NHibernate to store it in database. All
        // member variables are virtual for the same reason.
        public virtual Guid Id { get; set; }
        public virtual Int32 ScheduleBatchID { get; set; }
        public virtual Int32 PseudoSagaID { get; set; }
        public virtual String CreditCardNumber { get; set; }
        public virtual String ExpiryDate { get; set; }

        public virtual String AccountNumber { get; set; }
        public virtual String BSB { get; set; }

        public virtual Decimal Amount { get; set; }
        public virtual Int32 Firm_fk { get; set; }
        public virtual String FirmName { get; set; }
        public virtual TransactionType PaymentType { get; set; }
        // transaction number, max 15 chars, to use one of the following:
        public virtual int ApplicationPaymentInfo_fk { get; set; }
        public virtual BankRequestResponseSagaBase Parent { get; set; }
    }

如果我没有任何订阅,Bus.Publish()调用就可以了。如果我订阅了另一个服务,我会收到以下错误消息:

mscorlib.dll中出现未处理的“System.StackOverflowException”类型异常

除此之外没有关于溢出的更多信息:{无法计算表达式,因为当前线程处于堆栈溢出状态。}

我有自己的SagaPersister,Profile和SagaRegistry,但不确定它们是否与此问题相关,但如果需要可以提供它们。

2 个答案:

答案 0 :(得分:2)

堆栈溢出通常是由重入代码引起的(一种可以间接调用自身的方法。每次调用一个方法时,它会在堆栈上使用更多的空间,所以如果它自己调用它可以创建一个无限循环,耗尽所有堆栈。)

.net中可能存在一个错误,但是你的TimeOut事件处理程序更有可能在调用Timeout时仍然处理第一个调用导致另一个调用的情况,导致另一个调用,等等,导致无限循环。您是否在输出日志中收到大量“超时收到”文本?

避免这种情况的方法是:

  • 不要拨打导致可重入的电话
  • 在事件处理程序执行任何工作之前删除事件订阅(并可能在退出处理程序时重新订阅)
  • 使用bool变量或其他互锁来检测重入调用

答案 1 :(得分:2)

这里看起来有点可疑的是TransactionDetail对象上的BankRequestResponseSagaBase Parent属性。可能是你的引用中有一个循环导致你的saga persister爆炸。