由 Bus.Publish() 或订阅引起的 StackOverflowException?
我有一个代理,它使用传奇来跟踪给定类型的传入消息,直到收到超时消息。在超时处理程序中,我有以下内容:
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,但不确定它们是否与此问题相关,但可以在需要时提供它们。
I have an agent that employs a saga to track incoming messages of a given type until a Timeout message is received. In the Timeout handler, I have the following:
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 is an ICollection
Here is TransactionDetail class:
[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; }
}
If I don't have any subscriptions in place, the Bus.Publish() call goes through fine. If I have another service subscribed to it, I get the following error message:
An unhandled exception of type 'System.StackOverflowException' occurred in mscorlib.dll
There is no further information on the overflow other than this: {Cannot evaluate expression because the current thread is in a stack overflow state.}
I have my own SagaPersister, Profile and SagaRegistry but not sure if they are pertinent to this issue but can supply them if needed.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这里看起来有点可疑的一件事是 TransactionDetail 对象上的 BankRequestResponseSagaBase Parent 属性。可能是您的引用中有一个循环,导致您的传奇持久化程序崩溃。
The one thing that looks a bit suspicious here is the BankRequestResponseSagaBase Parent property on your TransactionDetail object. It could be that you have a loop in your references that is causing your saga persister to blow up.
堆栈溢出通常是由可重入代码(可能是间接调用自身的方法)引起的。每次调用方法时,它都会在堆栈上使用更多的空间,因此如果它调用自身,则可能会创建一个无限循环用完所有堆栈)。
.net 中可能存在错误,但更有可能的是,您的 TimeOut 事件处理程序正在调用某些内容,导致在处理第一个事件时再次调用 Timeout,从而导致另一次调用,依此类推,从而导致无限环形。您是否在输出日志中收到大量“已超时”文本?
避免这种情况的方法是:
A stack overflow is usually caused by re-entrant code (a method that calls itself, possibly indirectly. Each time a method is called, it uses a bit more space on the stack, so if it calls itself it can create an infinite loop which uses up all the stack).
It is possible there is a bug in .net, but it's more likely that your TimeOut event handler is calling something that causes another call to Timeout while it is still processing the first one, which causes another call, and so on, causing an infinite loop. Are you getting an enormous amount of "Timeout received" text in your output log?
Ways to avoid this situation are: