2

同じドキュメントを連続して複数回更新しようとすると、ConcurrencyException が発生し続けます。PUT attempted on document '<id>' using a non current etagがメッセージです。

UI から保存するたびに、MassTransit を使用してイベントを発行します。このイベントはサブスクライバー キューに送信されますが、イベント ハンドラーをオフラインにします (オフライン サブスクライバーをテストします)。イベントハンドラがオンラインになると、キューが読み取られ、メッセージが意図したとおりに処理されます。

ただし、同じオブジェクトが複数回キューにあるため、最初の書き込みは成功しますが、次の書き込みは成功せず、この同時実行例外がスローされます。

ファクトリ クラスを使用して、すべてのアプリケーションで一貫した IDocumentStore と IDocumentSession を保持しています。UseOptimisticConcurrency = falseGetSession() メソッドで具体的に設定します。

public static class RavenFactory
{
    public static IDocumentStore CreateDocumentStore()
    {
        var store = new DocumentStore() { ConnectionStringName = "RavenDB" };

        // Setting Conventions
        store.Conventions.RegisterIdConvention<MyType>((db, cmd, e) => e.MyProperty.ToString());
        store.Conventions.RegisterAsyncIdConvention<MyType>((db, cmd, e) => new CompletedTask<string>(e.MyProperty.ToString()));

        // Registering Listeners
        store
            .RegisterListener(new TakeNewestConflictResolutionListener())
            .RegisterListener(new DocumentConversionListener())
            .RegisterListener(new DocumentStoreListener());

        // Initialize and return
        store.Initialize();
        return store;
    }

    public static IDocumentSession GetSession(IDocumentStore store)
    {
        var session = store.OpenSession();
        session.Advanced.UseOptimisticConcurrency = false;
        return session;
    }
}

イベントハンドラはこんな感じ。IDocumentSession は、依存性注入を使用して注入されます。IDocumentSession のインスタンスを取得するロジックは次のとおりです。

private static void InitializeRavenDB(IUnityContainer container)
{
    container.RegisterInstance<IDocumentStore>(RavenFactory.CreateDocumentStore(), new ContainerControlledLifetimeManager());
    container.RegisterType<IDocumentSession, DocumentSession>(new PerResolveLifetimeManager(), new InjectionFactory(c => RavenFactory.GetSession(c.Resolve<IDocumentStore>())));
}

そして、これが ConcurrencyException を持つ実際の EventHandler です。

public class MyEventHandler:Consumes<MyEvent>.All, IConsumer
{
    private readonly IDocumentSession _session;

    public MyEventHandler(IDocumentSession session)
    {
        if (session == null) throw new ArgumentNullException("session");

        _session = session;
    }

    public void Consume(MyEvent message)
    {
        Console.WriteLine("MyEvent received: Id = '{0}'", message.MyProperty);

        try
        {
        _session.Store(message);
    _session.SaveChanges();
        }
        catch (Exception ex)
        {
            var exc = ex.ToString();
            // Deal with concurrent writes ...
            throw;
        }
    }
}

並行性への対処方法についてビジネスで整理できるようになるまで、現時点では並行性例外を無視したいと思います。

では、ConcurrencyException が発生する理由はありますか? ドキュメントが以前に更新されたかどうかに関係なく、保存が行われるようにします。

4

1 に答える 1

0

私は Unity の構成に慣れていませんが、常にシングルトンのIDocumentStore. 以下では、Singleton を手動でコーディングしましたが、Unity でサポートされると確信しています。

public static class RavenFactory
{
    private static IDocumentStore store;
    private static object syncLock = new object();

    public static IDocumentStore CreateDocumentStore()
    {
        if(RavenFactory.store != null) 
           return RavenFactory.store;

        lock(syncLock)
        {
           if(RavenFactory.store != null) 
              return RavenFactory.store;

           var localStore = new DocumentStore() { ConnectionStringName = "RavenDB" };

           // Setting Conventions
           localStore .Conventions.RegisterIdConvention<MyType>((db, cmd, e) => e.MyProperty.ToString());
           localStore .Conventions.RegisterAsyncIdConvention<MyType>((db, cmd, e) => new CompletedTask<string>(e.MyProperty.ToString()));

           // Registering Listeners
           localStore 
              .RegisterListener(new TakeNewestConflictResolutionListener())
              .RegisterListener(new DocumentConversionListener())
              .RegisterListener(new DocumentStoreListener());

           // Initialize and return
           localStore.Initialize();
           RavenFactory.store = localStore;
           return RavenFactory.store;
       }
    }

    //      As before
    //     public static IDocumentSession GetSession(IDocumentStore store)
    //
}
于 2014-10-14T13:05:47.280 に答える