I keep getting a ConcurrencyException trying to update the same document multiple times in succession. PUT attempted on document '<id>' using a non current etag
is the message.
On every save from our UI we publish an event using MassTransit. This event is sent to the subscriberqueues, but I put the Eventhandlers offline (testing offline subscribers). Once the eventhandler comes online the queue is read and the messages are processed as intended.
However since the same object is in the queue multiple times the first write succeeds, the next doesn't and throws this concurrencyexception.
I use a factory class to have a consistent IDocumentStore and IDocumentSession in all my applications. I specifically set the UseOptimisticConcurrency = false
in the GetSession() method.
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;
}
}
The eventhandler looks like this. The IDocumentSession gets injected using Dependency Injection. Here is the logic to get an instance of 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>())));
}
And here is the actual EventHandler which has the 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;
}
}
}
I want to ignore any concurrencyexception for now until we can sort out with the business on how to tackle concurrency.
So, any ideas why I get the ConcurrencyException? I want the save to happen no matter whether the document has been updated before or not.