gautema/CQRSlite

Session concurrency

DanBrk opened this issue · 11 comments

I have situation where commands are sent from different threads. The call of one thread to Session.Add is performed during Session.Commit of the other thread. it seems that the work with _trackedAggregates is not thread safe.

Hi. Is there a reason you use the same session from different threads? This sounds a bit strange to me. A session is meant to only be used from one thread. If more threads commits and adds at different times, it sound like there should be two different sessions to me. Is there a reason to reuse the same session? If local caching is the reason, CacheRepository which is thread safe can be used.

Hi and thank you for the advice. I do have scenarios where commands are executed in background threads. I fixed the problem by using transient scope for commands handlers and sessions.

That should do the trick. I'll close the issue, but just comment or reopen if there are any more problems.

Hi,
I have a problem of duplicate versions. The two last events show same version and I get EventsOutOfOrderException. From this point the aggregate cannot be updated.
This scenario occurs when the aggregate is updated from few commands running in different threads.
How should I avoid this problem ?

Hi.
Are you using optimistic concurreny? Also what database are you using and what kind of transaction isolation level are you using?

I am using optimistic concurrency. The events are stored in MongoDB and there is are no transactions.
My problem is that sessions process the same aggregate Id at the same time.
I thought of making the version parameter unique in MongoDB to avoid events with same version.
What is the best practice of supporting concurrency?

Thank you.

Hi.
If you are using session most should be handled for you. But you do have to use some sort of database transaction around saving a session, since it reads, applies, and then saves events. If there are no transaction scope, things can change between read and save and cause the kinds of errors you see.

I don't know MongoDb well enough to know just how uniqueness on fields work, but it sounds like that should do what you want.

Hi,
In MongoDb uniqueness will ensure for me that aggregate with the same version number can not be saved. It is a good work around solution.

I thought maybe there is a way to avoid that in Session.Get() but I understand that some type of transaction or distributed lock is required to avoid different sessions from different threads or processes to work on that same aggregate version.

Thanks a lot for the advice

I'm not sure I understood you completely, but you should only need to have a transaction around Session.Commit, since it then checks if new events have occured.

Sorry I didn't make myself clear. I am not sure I understand the CacheRepository.

  1. In the example the MemoryCache is singleton. is it for the thread safe ?
  2. Will it be safer to use Redis cache instead of MemoryCache ?

Hi.
I don't recall completely, but I think the only reason MemoryCache is a singleton is because it can be.
I don't think Redis is any safer than MemoryCache but there are some advantages to taking it out of process. It can be shared between different machines and lets you have better control over memory usage. But it will be a bit slower