Concurrency RavenDB不断抛出并发异常
我不断收到一个并发异常,试图连续多次更新同一文档<代码>尝试使用非当前etag对文档“”执行PUT操作是消息 每次从UI保存时,我们都会使用MassTransit发布一个事件。此事件被发送到subscriberqueues,但我将EventHandler置于脱机状态(测试脱机订阅者)。一旦eventhandler联机,将读取队列并按预期处理消息 但是,由于同一对象多次出现在队列中,因此第一次写入成功,下一次写入失败,并引发此concurrencyexception 我使用工厂类在所有应用程序中具有一致的IDocumentStore和IDocumentSession。我在GetSession()方法中专门设置了Concurrency RavenDB不断抛出并发异常,concurrency,ravendb,optimistic-concurrency,Concurrency,Ravendb,Optimistic Concurrency,我不断收到一个并发异常,试图连续多次更新同一文档尝试使用非当前etag对文档“”执行PUT操作是消息 每次从UI保存时,我们都会使用MassTransit发布一个事件。此事件被发送到subscriberqueues,但我将EventHandler置于脱机状态(测试脱机订阅者)。一旦eventhandler联机,将读取队列并按预期处理消息 但是,由于同一对象多次出现在队列中,因此第一次写入成功,下一次写入失败,并引发此concurrencyexception 我使用工厂类在所有应用程序中具有一致的
UseOptimisticConcurrency=false
公共静态类RavenFactory
{
公共静态IDocumentStore CreateDocumentStore()
{
var store=new DocumentStore(){ConnectionStringName=“RavenDB”};
//设定惯例
store.Conventions.RegisterIdConvention((db,cmd,e)=>e.MyProperty.ToString());
RegisterAsyncIdConvention((db,cmd,e)=>newcompletedtask(e.MyProperty.ToString());
//注册听众
商店
.RegisterListener(新建TakeNewestConflictResolutionListener())
.RegisterListener(新文档转换Listener())
.RegisterListener(新的DocumentStoreListener());
//初始化并返回
store.Initialize();
退货店;
}
公共静态IDocumentSession GetSession(IDocumentStore存储)
{
var session=store.OpenSession();
session.Advanced.UseOptimisticConcurrency=false;
返回会议;
}
}
eventhandler如下所示。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>())));
}
private静态无效初始值设定项eravendb(IUnityContainer容器)
{
container.RegisterInstance(RavenFactory.CreateDocumentStore(),新的ContainerControlledLifetimeManager());
RegisterType(new PerResolveLifetimeManager(),new InjectionFactory(c=>RavenFactory.GetSession(c.Resolve()));
}
这里是实际的EventHandler,它具有ConcurrencyException
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;
}
}
}
公共类MyEventHandler:Consumes.All,IConsumer
{
私有只读IDocumentSession\u会话;
公共MyEventHandler(IDocumentSession)
{
如果(session==null)抛出新的ArgumentNullException(“session”);
_会话=会话;
}
公共void消费(MyEvent消息)
{
WriteLine(“MyEvent接收到:Id='{0}',message.MyProperty);
尝试
{
_会话存储(消息);
_session.SaveChanges();
}
捕获(例外情况除外)
{
var exc=ex.ToString();
//处理并发写入。。。
投掷;
}
}
}
我想暂时忽略任何并发例外,直到我们能够与业务部门就如何解决并发性进行协调
那么,你知道我为什么会得到ConcurrencyException吗?我希望无论文档之前是否已更新,都能进行保存。我不熟悉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)
//
}
公共静态类RavenFactory
{
私人静态IDocumentStore;
私有静态对象syncLock=新对象();
公共静态IDocumentStore CreateDocumentStore()
{
if(RavenFactory.store!=null)
返回RavenFactory.store;
锁定(同步锁定)
{
if(RavenFactory.store!=null)
返回RavenFactory.store;
var localStore=new DocumentStore(){ConnectionStringName=“RavenDB”};
//设定惯例
localStore.Conventions.RegisterIdConvention((db,cmd,e)=>e.MyProperty.ToString());
RegisterAsyncIdConvention((db,cmd,e)=>newcompletedtask(e.MyProperty.ToString());
//注册听众
本地存储
.RegisterListener(新建TakeNewestConflictResolutionListener())
.RegisterListener(新文档转换Listener())
.RegisterListener(新的DocumentStoreListener());
//初始化并返回
localStore.Initialize();
RavenFactory.store=localStore;
返回RavenFactory.store;
}
}
//一如既往
//公共静态IDocumentSession GetSession(IDocumentStore存储)
//
}
看看这个,它可能会帮助您解决近一年来出现的并发问题,您找到解决方案了吗?有人发现了吗?似乎只有一种文档类型保存在处理程序中,其他所有文档类型都保存得很好@GuillaumeSchuermans:这个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)
//
}