2012-01-09 3 views
1

У меня есть агент, который использует сага для отслеживания входящих сообщений определенного типа до получения сообщения Timeout. В обработчике тайм-аута, у меня есть следующие:StackOverflowException вызвано Bus.Publish() или подпиской?

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; } 
    } 

Если у меня нет подписки в месте, автобус .Publish() звонит через штраф. Если я еще одна услуга подписки на него, я получаю следующее сообщение об ошибке:

Необработанное исключение типа «System.StackOverflowException» произошло в mscorlib.dll

Там нет никакой дополнительной информации о переполнении, кроме этого : {Невозможно оценить выражение, потому что текущий поток находится в состоянии переполнения стека.}

У меня есть собственный SagaPersister, Profile и SagaRegistry, но не уверен, что они относятся к этой проблеме, но могут поставлять их в случае необходимости.

ответ

2

Единственное, что выглядит немного подозрительно вот BankRequestResponse Свойство SagaBase Parent в вашем объекте TransactionDetail. Может быть, у вас есть петля в ваших ссылках, из-за которой ваш сага-стражник взрывается.

+0

Я удалил там ссылку и прибрал пару других линий, и она перестала рушиться. Поблагодарите Уди, постарайтесь прийти и увидеть вас в Сиднее. – Fellmeister

2

Переполнение стека обычно вызвано повторным входящим кодом (метод, который вызывает себя, возможно, косвенно. Каждый раз, когда вызывается метод, он использует в стеке больше места, поэтому, если он вызывает себя, он может создавать бесконечный цикл, который использует весь стек).

Возможно, есть ошибка в .net, но более вероятно, что обработчик события TimeOut вызывает то, что вызывает другой вызов таймаута, пока он все еще обрабатывает первый, что вызывает другой вызов, и так далее , вызывая бесконечный цикл. Получаете ли вы огромное количество текста «Timeout received» в вашем журнале вывода?

Пути, чтобы избежать этой ситуации являются:

  • Не делайте вызовы, которые вызывают Реентерабельность
  • удалить подписку на событие в обработчике событий, прежде чем он делает любую работу (и, возможно, повторно подписать его на выходе из обработчика)
  • использовать переменный Ий или другой блокиратор для обнаружения Реентрантного вызывает
+0

Вы, rpost, были полезны в другом приложении, которое я написал. Спасибо, что потратили время. – Fellmeister