我一直在尝试连续多次更新同一文档时遇到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的任何想法?无论文档之前是否更新过,我都希望保存发生。
答案 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)
//
}