由Bus.Publish()或订阅引起的StackOverflow异常

本文关键字:StackOverflow 异常 Publish Bus | 更新日期: 2023-09-27 18:19:50

我有一个代理,它使用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,但不确定它们是否与这个问题有关,但如果需要,可以提供它们。

由Bus.Publish()或订阅引起的StackOverflow异常

这里看起来有点可疑的是TransactionDetail对象上的BankRequestResponseSagaBase Parent属性。这可能是因为你的参考资料中有一个循环,导致你的传奇故事持续不断。

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

.net中可能存在错误,但更有可能的是,您的TimeOut事件处理程序在处理第一个调用时调用了导致另一个TimeOut调用的东西,从而导致了另一个调用,依此类推,从而导致无限循环。您的输出日志中是否有大量"收到超时"文本?

避免这种情况的方法有:

  • 不要进行导致重新进入的调用
  • 在事件处理程序中删除事件订阅,然后再执行任何操作(并可能在退出处理程序时重新订阅)
  • 使用bool变量或其他互锁来检测再入调用