2

我不断收到 ConcurrencyException 尝试连续多次更新同一个文档。PUT attempted on document '<id>' using a non current etag是消息。

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

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

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

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. 下面,我手动编写了单例,但我确信 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 回答