我们有一个处理多种消息类型的NServiceBus实现:
public class StateCoordinator : Saga<MessageData>,
IAmStartedByMessages<CreateMessage>,
IAmStartedByMessages<ConfirmMessage>
MessageData是这样的:
public class FlowData : IContainSagaData
{
[Unique]
public Guid MappingId { get; set; }
public Guid Id { get; set; }
public string OriginalMessageId { get; set; }
public string Originator { get; set; }
public List<MessagePart> MessageParts { get; set; }
}
public MessagePart
{
public int Id { get; set; }
public string Status { get; set; }
}
CreateMessage有一个MessagePart,它被添加到其处理程序中的MessagePart中。 ConfirmMessage更新特定MessagePart的状态。
这是情景:
1)收到第一个CreateMessage。这在Raven中创建了Saga,并在MessageParts中添加了一个MessagePart(状态为#34; 1&#34;)。
2)收到第一个ConfirmMessage。这会将Saga中第一个添加的MessagePart的状态更新为&#34; 1 2&#34;。当转到RavenDB中的文档时,这在浏览器中是可见的。
3)收到第二个CreateMessage。这为MessageParts添加了第二个MessagePart。在查看数据时,第一个MessagePart的状态仍然是&#34; 1&#34;而不是&#34; 1 2&#34;这会引发并发异常(ActualETag不等于ExpectedETag):
A first chance exception of type 'Raven.Abstractions.Exceptions.ConcurrencyException' occurred in Raven.Client.Lightweight
Additional information: PUT attempted on document 'flow/79a7ee20-f090-4648-9b62-a3da00d87c93' using a non current etag
看起来每个消息类型都缓存了Saga数据。是这样吗?有解决方案吗?
注:
我们正在使用多个IAmStartedByMessages,但是当ConfirmMessage在CreateMessage之前时,则会将此消息添加到队列中,直到处理完CreateMessage。
答案 0 :(得分:2)
经过几次测试后,我可以说没有真正的问题。我认为你无法解决并发异常(记录此异常),但是当发生此异常时,消息只是发送回队列进行重试。
我担心Handle的逻辑会被执行两次,但我想因为我启用了事务,所以情况并非如此。例如:其中一个操作是将消息发送到另一个总线以持久保存事件(perister-queue)。在异常发生之前调用此操作(在句柄之后,数据保存在Saga中并抛出异常)但是没有消息添加到persister-queue。重试成功的消息后(这会更新数据,因此不再存在并发异常),persister-message将添加到persister-queue。
结论:不是真正的问题,只是日志文件中的额外行。