重用 NServiceBus 消息传奇数据
是否有任何理由不在 saga 数据中重用 NServiceBus 消息 (IMessage
)?我的意思是有一条像这样的消息:
public class Order : IMessage
{
public virtual List<TillOrderLine> OrderLines { get; set; }
}
public class TillOrderLine : IMessage { ... }
然后也在 saga 和 saga 数据中使用它,如下所示:
public class OrderProcessingSaga :
Saga<OrderProcessingSagaData>,
IAmStartedByMessages<Order> { ... }
public class OrderProcessingSagaData : ISagaEntity
{
public virtual Guid Id { get; set; }
public virtual string Originator { get; set; }
public virtual string OriginalMessageId { get; set; }
// The message data is stored by the saga here.
public virtual Order Order { get; set; }
}
我意识到消息是由传输层(MSMQ)存储的,而 saga 数据则通过以下方式保存到数据库:传奇。它适用于我当前的用例,并且重用该类似乎更优雅,而不是为消息创建一个类,为传奇存储创建另一个类。
我想知道这种方法是否有任何问题?
Are there any reasons not to reuse an NServiceBus message (IMessage
) in saga data? What I mean is having a message something like this:
public class Order : IMessage
{
public virtual List<TillOrderLine> OrderLines { get; set; }
}
public class TillOrderLine : IMessage { ... }
And then also using it in the saga and saga data like this:
public class OrderProcessingSaga :
Saga<OrderProcessingSagaData>,
IAmStartedByMessages<Order> { ... }
public class OrderProcessingSagaData : ISagaEntity
{
public virtual Guid Id { get; set; }
public virtual string Originator { get; set; }
public virtual string OriginalMessageId { get; set; }
// The message data is stored by the saga here.
public virtual Order Order { get; set; }
}
I realise that the message is stored by the transport layer (MSMQ), whilst the saga data is persisted to DB with the saga. It works for my current use case and seems more elegant to reuse the class rather than creating one for the message and another for saga storage.
I'm wondering if there are any gotchas with this approach?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我同意 mookid8000 所说的一切,但我还有一个细节需要补充。
您的传奇存储通常会存在很多争用。为了保证一致性,saga 存储提供程序通常会在数据上放置更新锁,以保证来自同一 saga 的另一条消息不能同时改变状态。
如果您使用默认的 NHibernate saga 持久化程序(并且您的虚拟属性向我表明您是这样),那么 NHibernate 使用一些假设来保存您的数据:
无论如何,saga persister 需要将数据拆分成的表越多,就越难使用细粒度行锁来锁定涉及的行。如果有足够的争用,行锁将开始升级为页锁和表锁,然后你就真的遇到了问题。
这就是为什么文档数据库真正适合 saga 存储,这就是为什么在 NServiceBus 3.0 中他们将 RavenDB 设为默认的 saga 持久化器。
在此之前,请查看基于 XML 序列化的 Saga Persister我写道,它可以为您今天的应用程序带来即将推出的 RavenDB 风格的传奇持久化程序的一些好处。
如果您必须坚持使用 NHibernate,我强烈建议您不要将消息与 saga 持久性解决方案紧密结合在一起。我几乎可以保证它会在路上再次困扰你。
I agree with everything mookid8000 said, however I have one more detail to add.
There can commonly be a lot of contention on your saga storage. To guarantee consistency, the saga storage provider will commonly place update locks on the data to guarantee that another message from the same saga can't mutate state at the same time.
If you are using the default NHibernate saga persister (and your virtual properties suggests to me that you are) then NHibernate uses some assumptions in order to save your data:
In any case, the more rows in the more tables the saga persister is required to split your data into, the harder it is to lock the involved rows with granular row locks. With enough contention, row locks will start to escalate to page locks and table locks and then you've really got a problem.
This is why a document database would really shine for saga storage, which is why in NServiceBus 3.0 they are making RavenDB the default saga persister.
Until then, take a look at the XML Serialization based Saga Persister I wrote, which can bring some of the benefits of the upcoming RavenDB-style saga persister to your application today.
If you must stick with NHibernate, I would strongly discourage you to couple your messages so tightly with your saga persistence solution. I almost guarantee it will come back to haunt you down the road.
如果您当前的传奇持久化者没有抱怨地坚持数据,我想不出这种方法有什么问题 - 只要您意识到您正在出于两个目的重用一个类,从而在传奇数据(这是私有的)之间引入耦合 。
然后,如果您需要偏离消息的结构方式,您可以为所有 saga 数据构建类
PS:如果
TillOrderLine
的唯一目的是在Order
内聚合,则无需将其标记为IMessage
。If your surrent saga persister persists the data without complaining, I cannot think of anything wrong with this approach - as long as you're conscious that you're reusing a class for two purposes, thus introducing a coupling between saga data (which is private to the service) and messages (which are inherently public) regarding fields present, naming, etc.
Then you can build classes for all of your saga data if and when you need to deviate from the ways your messages are structured.
PS:
TillOrderLine
doesn't need to be marked asIMessage
if its only purpose is to be aggregated insideOrder
.