1

clientChangeMes​​sage(クライアントの作成を担当)とclientContractChangeMEssage(クライアントの予約の詳細を担当)の2つのメッセージがあります。現在、私のデータベースでは、クライアント コントラクトがあるまでクライアントを作成できません。私のローカル システムではすべて正常に動作しています。つまり、最初にクライアント変更メッセージを取得した場合、それを saga に保存し、クライアント コントラクト メッセージを待ちます。それが到着すると、saga は両方のメッセージを実行します。しかし、私のテスター マシンでは、クライアント変更メッセージが来るとサガに保存されますが、クライアント コントラクトの変更が来ると、サガはクライアント変更サガを見つけられず、別のサガを作成します。テスターが試したのとまったく同じメッセージで試してみましたが、私のマシンで動作し、何が問題なのかわかりません。私はraven dbの永続性を使用しています。(申し訳ありませんが、これにコードを貼り付けることは考えられませんでした)

ClientSagaState

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();


       }

ありがとう、

4

1 に答える 1

1

ClientRef プロパティを介して saga データにマッピングしているため、このプロパティが一意であることを永続性 (この場合は Raven) に伝える必要があります。おそらく発生しているのは、場合によっては (競合状態になる)、2 番目のメッセージによって Raven インデックスに対して実行されたクエリが古いデータを取得し、saga データがないと想定して、新しいデータを作成することです。

これで問題が解決するはずです:

[Unique]
public Guid ClientRef { get; set; }

この情報を使用して、Raven サガ パーシスタはこのプロパティに基づいて追加のドキュメントを作成し (Raven での Id による読み込みは完全にアトミックであるため)、2 番目のメッセージが確実にそれを見つけられるようにします。

NHibernate などの別の永続化メディアを使用している場合、同じ属性を使用してその列に一意のインデックスを作成します。

コメントに基づいて編集

一意の制約ドキュメントと saga データは完全に一致するため、着信メッセージのタイミングに応じて、3 つのいずれかが発生します。

  1. メッセージは実際に到着して処理される最初のメッセージであるため、saga データが見つからないため、作成されます。
  2. メッセージは 2 番目に到着するので、saga データを探して見つけ、正常に処理します。
  3. 2 番目のメッセージは最初のメッセージのすぐ近くに到着するため、両方とも別々のスレッドで同時に処理されます。両方のスレッドが saga データを調べても何も見つからないため、両方とも処理を開始します。最初にコミットを完了したものは、正常にコミットされ、そのサガ データが保存されます。saga データを保存するための 2 回目の試行を終了したスレッドが、作業中に他のスレッドがチーズを移動したことが判明したため、Raven は同時実行例外をスローします。メッセージはキューに戻って再試行されます。サガ データが存在するため、再試行はシナリオ #2 のように機能します。
于 2013-10-23T14:40:56.940 に答える