Reputation: 3095
I'm using RavenDB as denormalized read model populated from domain events. I found problem, when two events (let's call them Created and Updated) are denormalized in the same time, loading document to be updated by Updated event occurs before saving changes made by Created event. I've came up with solution based on Changes API to wait for document creation:
public static T WaitAndLoad<T>(this IDocumentSession @this, ValueType id)
where T : class
{
var fullId = @this.Advanced.DocumentStore.Conventions.FindFullDocumentKeyFromNonStringIdentifier(id, typeof(T), false);
var ev = new ManualResetEvent(false);
var cancelation = new CancellationTokenSource();
@this.Advanced.DocumentStore
.Changes()
.ForDocument(fullId)
.Subscribe(change =>
{
if (change.Type == DocumentChangeTypes.Put)
{
ev.Set();
}
}, cancelation.Token);
try
{
var existing = @this.Load<T>(id);
if (existing != null)
{
return existing;
}
ev.WaitOne();
return @this.Load<T>(id);
}
finally
{
cancelation.Cancel();
}
}
Unfortunately second call to Load returns null because Id of document is already in knownMissingIds field in InMemoryDocumentSessionOperations and no request to server is made.
It there any other way to wait until document is created?
Upvotes: 1
Views: 239
Reputation: 241525
Well, I'm not sure what mechanism you are using for event processing, but I have been in a similar situation with something like NServiceBus. I don't think this exactly a RavenDB problem. You would probably have the same issue if you were writing to a SQL Server database.
The generalized problem is, Create
and Update
events are fired off, but they are received and processed in the wrong order. What to do?
Well the general advice is that your event handlers should be idempotent, and should retry when failed. So if Update
is received first, it will throw an exception and be scheduled for retry. Then Create
comes through, then Update
retries and all is good.
Specifically blocking and waiting in the handler for the Update
event is not advised, because if you had several of these then they could block all worker threads and the Create
events would never come through.
Upvotes: 2