There is a problem on the persistence side of our models: concurrent updates. Some of us apply the technique of last-one-wins, by not protecting against simultaneous modifications of an entity. This can be OK in most cases (like CRUD) but when we have calculations to do based on the previous values we encounter problems. I encountered this situation on my event-based architectures when the read models are updated as the events arrive.

But let’s start with an example: Let’s suppose that we have a simple product entity that can be rated and we only need to provide the average rating and the number or ratings. So, our model would look something like this:

We would be in big trouble if two events arrive at the same time: both the product loading are done (lets suppose the previous rating count would be 100), then both add a rating (the new rating count becomes 101, for each operation) then the new rating is persisted (so 101 rating count is persisted, by the last operation); this is bad because there were 100 ratings and after two more arrived only one had effect. Please notice that the protection that the underlying database is providing us is not helpful (row locking, document locking, whatever).

So, how to add both of the ratings, even if they arrive at the same time? The answer is: by retrying the whole load-calculate-persist process. This is called optimistic locking.

But for this to work you have to detect concurent updates and not succeed if a previous update was done. For this you need to have a version property on your entity. This version is the version that existed when the entity was loaded and when you try to persist the changes to the entity you check that the current version is equal to that loaded version. If the stored entity has a new version then that means that you based your calculations upon an old version of that entity and you must retry.

In order to extract this algorithm into a class we make a Versionable interface like this:

It is OK to use not-type-hinted callables because this is a private manner. To use the same abstraction level in our event handler I have extracted a new method: private function update. This method accepts the ProductId, the factory callable (is called if the product does not exist yet) and the updater function that would perform the actual update on the product.

So, the idea of this updater is that it tries to update the know version of an entity. If that version does not exist anymore, then the whole process is restarted.
Another important detail is that the version is incremented atomically, in the same time as the actual update, using the $inc operator.
You have now a concurrent-proof MongoDB entity updater 🙂