首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用raven db持久性的Saga错误nservicebus

使用raven db持久性的Saga错误nservicebus
EN

Stack Overflow用户
提问于 2013-10-23 10:52:06
回答 1查看 782关注 0票数 1

我有两条消息,clientChangeMessage(负责创建客户端)和clientContractChangeMEssage(负责客户端的预订细节)。现在,在我的数据库中,客户端只有在拥有客户端契约之后才能创建,反之亦然。在我的本地系统上,一切正常,即,如果首先获得客户端更改消息,我将其存储在saga中,等待客户合同消息,当消息到达时,saga执行这两条消息。但是,在我的测试人员机器上,当客户更改消息出现时,它会存储在传奇中,但是当客户合同发生更改时,saga不会找到客户更改消息,因此会创建另一个saga。我已经尝试了与我的测试人员尝试过的完全相同的消息,它在我的机器上工作,并且无法找出可能出了什么问题。我使用的是乌鸦数据库持久化。(对不起,我想不出为此粘贴任何代码)

ClientSagaState

代码语言:javascript
复制
public class ClientSagaState:IContainSagaData
    {
        #region NserviceBus
        public Guid Id { get; set; }
        public string Originator { get; set; }
        public string OriginalMessageId { get; set; }
        #endregion

        public Guid ClientRef { get; set; }

        public ClientMessage ClientChangeMessage { get; set; }

        public ClientContractChangeMessage ClientContractChange { get; set; }


    }


    public  class ClientSaga:Saga<ClientSagaState>,
           IAmStartedByMessages<ClientChangeMessage>,
           IAmStartedByMessages<ClientContractChangeMessage>
       {

        public override void ConfigureHowToFindSaga()
           {

               ConfigureMapping<ClientChangeMessage>(s => s.ClientRef, m => m.EntityRef);
               ConfigureMapping<ClientContractChangeMessage>(s => s.ClientRef, m => m.PrimaryEntityRef);
           }

        public void Handle(ClientChangeMessage message)
           {

               if (BusRefTranslator.GetLocalRef(EntityTranslationNames.ClientChange, message.EntityRef.Value) != null)
               {

                   GetHandler<ClientChangeMessage>().Handle(message);
                   CompleteTheSaga();
                   return;
               }
               HandleServiceUserChangeAndDependencies(message);
               //MarkAsComplete();
               CompleteTheSaga();
           }

          public void Handle(ClientContractChangeMessage message)
            {
                var state=this.Data;
                //Some handling logic
                //Check if client is not in database then store the state
                state.ClientContractChange=message;
                state.ClientRef =message.PrimaryEntityRef;
                //if client is in the data base then 
                MarkAsComplete();


       }

谢谢,

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-10-23 14:40:56

因为您要通过ClientRef属性映射到saga数据,所以需要告诉持久性(在本例中是Raven),该属性是唯一的。可能发生的情况是,在某些情况下(可以归结为竞争条件),第二条消息对Raven索引执行的查询会检索陈旧的数据,假设没有saga数据,并创建新的。

这应该可以解决您的问题:

代码语言:javascript
复制
[Unique]
public Guid ClientRef { get; set; }

有了这些信息,Raven saga持久器将根据该属性创建一个附加文档(因为Raven中的按Id加载是完全原子化的),因此第二条消息将确保找到它。

如果您使用另一种持久性介质(如NHibernate ),则将使用相同的属性在该列上构造唯一的索引。

基于评论的编辑

唯一的约束文档和您的saga数据将完全一致,因此取决于传入消息的时间,其中一件事将发生。

  1. 该消息确实是第一条到达并被处理的消息,因此没有找到saga数据,因此创建了该消息。
  2. 消息是第二个到达的,所以它查找saga数据,找到它,并成功地进行处理。
  3. 第二条消息非常接近第一条消息,因此它们同时在单独的线程中进行处理。两个线程都在查看saga数据而什么也找不到,所以它们都开始处理。第一个完成的成功提交并保存其传奇数据。完成第二次尝试保存saga数据的线程发现,当它工作时,另一个线程移动了它的奶酪,因此Raven抛出了一个并发异常。您的消息返回到队列中,并被重新尝试,现在已经存在了saga数据,重试就像场景2一样。
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19539666

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档