Concurrency control

From Sense/Net Wiki
Jump to: navigation, search
  •  
  •  
  •  
  •  
  • 100%
  • 6.0
  • Enterprise
  • Community
  • Planned

Overview

Concurrency in Sense/Net

In an enterprise environment, where there are lots of content to manage by lots of users, concurrency is a key factor. In case of Sense/Net ECMS content are stored in the Content Repository. This article provides concepts and best practices for developers on how to handle concurrency during creating and modifying content. To read more about the fundamentals of concurrency control please proceed to the Wikipedia article.

Details

The issue

We try to make creating and modifying content as fast as we can. However in a real enterprise environment, when in-memory cache is widely used and there is a chance that different users want to modify the very same content at the same time, it is physically impossible to make sure that saving operations do not collide. There are different approaches to control these kind of situations. In Sense/Net ECMS we chose the optimistic approach to handle concurrency. This means we do not use locking for performance reasons. When somebody loads, modifies and tries to save a content that has been modified by somebody else in the meantime, an exception will be thrown of type NodeIsOutOfDateException. It is the responsibility of the caller to handle this exception and choose the right solution:

  • try to save the content again, or
  • present the error to the user and let him decide what to do

The following section describes why we cannot retry saving the content automatically.

Why automation does not work

The process is the following

  • load the content
  • modify the content (a couple of fields)
  • save the content

It is possible that in the meantime somebody else modified the content. Or in a more complex situation, if the business logic loads and saves the same content multiple times, concurrency error may occur. Either way, if a NodeIsOutOfDateException was thrown, developers have to do one of the following:

  • use the field values of the old content and save it again, thus overriding the work of the previous user
  • reload the content and save it with the same field values we tried to add
  • reload the content and revise the modifiable field values according to the fresh content

The point is, any of the solutions above can be correct: it depends on the business logic which approach should we choose. The following section describes a pettern you may use to handle this situation.

The pattern to use

The following pattern demonstrates how to handle NodeIsOutOfDateException when it is possible to save the content again, without user interaction.

var retryMaxCount = 3;             // maximum number of attempts
var cycles = 0;                    // current attempt
Exception exception = null;        // inner exception storage
while (cycles++ < retryMaxCount)   // cycle control
{
    // loading the content
    var content = Content.Load("/Root/MyDocument");
 
    // modifying the content according to user interface or service request
    content["MyField"] = "MyValue";
    content["MyNumber"] = 42;
 
    // saving the content and detecting error
    try
    {
        content.Save();
 
        // successful save, exit loop
        exception = null;
        break;
    }
    catch (NodeIsOutOfDateException e)
    {
        exception = e; // storing the exception temporarily
    }
}
 
// rethrow if needed
if (exception != null)
    throw new ApplicationException("Node is out of date after 3 attempts.", exception);

Related links

References