RavenDB不断抛出ConcurrencyException

时间:2013-07-31 07:05:07

标签: concurrency ravendb optimistic-concurrency

我一直在尝试连续多次更新同一文档时遇到ConcurrencyException。 PUT attempted on document '<id>' using a non current etag就是消息。

在我们的UI中的每次保存中,我们使用MassTransit发布一个事件。此事件将发送到订阅者队列,但我将Eventhandler置于脱机状态(测试脱机订阅者)。一旦事件处理程序联机,就会读取队列并按预期处理消息。

但是,由于同一个对象在队列中多次,第一次写入成功,下一次写入并不会引发此并发异常。

我使用工厂类在我的所有应用程序中都有一致的IDocumentStore和IDocumentSession。我在GetSession()方法中专门设置了UseOptimisticConcurrency = false

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,直到我们可以解决有关如何解决并发问题的业务。

那么,为什么我得到ConcurrencyException的任何想法?无论文档之前是否更新过,我都希望保存发生。

1 个答案:

答案 0 :(得分:0)

我不熟悉配置Unity,但您总是想要IDocumentStore的Singleton。下面,我已经手动编写了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)
    //
}