Note that there are some explanatory texts on larger screens.

plurals
  1. POOptimisticConcurrencyException: Multiple EF based applications using shared AppFabric cache and same database
    primarykey
    data
    text
    <p>I am using a web application and a windows service on the same machine as Appfabric. Both applications reuse same DAL code (dll) which is EF (Entity Framework) Code-First based and accessing the same cache in Appfabric. The code in the windows service is implemented as a Job as part of <a href="http://quartznet.sourceforge.net/" rel="nofollow">Quartz.Net</a></p> <p>The web application has to support multiple requests off course, and the windows service multiple threads( scheduler and events). For both, the shared DAL dll creates a DbContext object per http session and thread ContextID or just Thread ContextID for the later. The DAL uses the EFCachingProviders from <a href="http://code.msdn.microsoft.com/EFProviderWrappers" rel="nofollow">here</a>. Also, my EF solution uses Optimistic concurrency with a timestamp columns and IsRowVersion in the mapping.</p> <p>As stated <a href="http://msdn.microsoft.com/en-us/magazine/hh394143.aspx" rel="nofollow">here</a>, the benefit of having a 2nd level cache is to have access to a representation of the original state across processes! But that does not seem to work for me, I get 'OptimisticConcurrencyException' in my use case as following:</p> <ol> <li>restart cache cluster, restart windows service, restart iis -> clean slate :)</li> <li>Using web app (firefox), I insert a new object A with reference to existing object B. I can see the new row in the database. All ok.</li> <li>Using webapp in another browser (chrome) = new session, i can see the new object.</li> <li>Next, the windows service tries to do some background processing and tries to update object B. This results in an 'OptimisticConcurrencyException'. Apparently the process in the windows service is holding a version of Object B with a dated rowversion.</li> <li>If i restart the windows service, it tries the same logic again and works with no exception....</li> </ol> <p>So both applications are multithreaded, use same DAL code, connect to same database, and same cache cluster and same cache. I would expect the update and insert to be in the appfabric cache. I would expect the EF context of the windows service to use the newest information. Somehow, it seems, that it's 1st level cache in holding on old information... or something else is going wrong.</p> <p>Please advice... </p> <p><strong>Update</strong></p> <p>Ok, after digging around, i fixed the Update problem of my windows service. Each Manager object with queries the DAL uses a DbContext bound to its Process ID + Thread ID. So in the Execute function of my Quartz Job, all Managers (of different object types) should share the same DbContext which is created by the first Manager.</p> <p>The problem was, that after the function finished, the DbContext was not Disposed (which happens automatically in the HTTP Session based DbContext manager). So the next time the Job was executed, the same DbContext was found and used, which by that time was dated already (old first level cache???). The 2nd level cache should not be a problem, because that is shared and SHOULD contain newest objects... if any.</p> <p>So this part is fixed.</p> <p><strong>New problem</strong></p> <p>So the web-app creates a new object A, updates an existing object B, the windows-service now works and is able to update the existing (changed) object B with no problem.</p> <p>Problem: When i do a refresh of the webapp, it does not see the changes (by the windows service) of object B....</p> <p>So if the webapp changed a count to 5, 10 minutes later the windows service change that count to 6 and I open the web-app in same or new window/browser, i still see 5, not 6!</p> <p>A restart of the webapp (iis) does not help, also an iisreset doesn't. When i do Restart-CacheCluster.... it works and shows 6....</p> <p>So it looks like the item is in the cache. The windows service updates it, but does not invalidate the item, which is old and used by the webapp....</p> <p>Or... although the same object, the webapp has its own entry in the cache and the win-app has its own entry (which does get invalidated)....</p> <p>Which one?</p> <p><strong>Solution</strong></p> <p>I solved this myself. The EF wrapper uses the query string as a key to store items in the cache, it seems. So 2 different queries (does not matter if they originate from 2 different application sharing same distributed cache or same application) referencing the same data in the database will have <strong>different</strong> keys (different query string) and so different places in the cache. Perhaps its not this black-and-white but something like this... </p> <p>I don't think internally some way of algorithm is used to check if a query touches existing cached objects.</p> <p>This causes my problem where my windows service does an update and the webapp still sees the old one from the cache which could only be solved by doing a Restart-CacheCluster command.</p> <p>So how i fixed this: My windows Service is a batch job triggered by the Quartz Scheduler. After it is done I clear the whole cache:</p> <pre><code>private void InvalidateCache() { try { DataCache myCache = ... foreach (String region in myCache.GetSystemRegions()) { myCache.ClearRegion(region); } } catch (Exception ex) { eventLog.WriteEntry("InvalidateCache exception : " + ex.Message); } } </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload