Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WCF webservice - is using lock going to cause problems?

We have a WCF web service operation that is used to generate PDF files. We're using a 3rd party tool to do that (Syncfusion specifically) which we may not be able to replace at the moment.

The problem is that it seems that 3rd party tool has a problem with multi-threading and doesn't work in some cases when there's multiple calls to the web service at the same time.

We can get rid of the problem by using lock and making sure that only one thread executes the critical section:

Public Class GeneratorController
{
    // object we use for lock
    private static Object thisLock = new Object();

    public void Generate(ref PdfDocument pdfDocument)
    {
        lock (thisLock)
        {
             // critical section
        }
    }
}

My questions is: is that a good idea? Is it going to cause any problems if we have a code like that in a web service?

Note

This is not a question about Syncfusion. This is a question about using lock in a web service. Do not change tags to syncfusion, please.

like image 687
Szymon Avatar asked Oct 09 '13 03:10

Szymon


2 Answers

The problem I see here is resource starvation.

There is no FIFO rule surrounding locks. So if there's a continuous load, you could get this scenario:

  • Thread A claims the lock
  • Thread B waits for the lock
  • Thread C waits for the lock
  • Thread A releases the lock. The lock is arbitrarily given to thread C
  • Thread D waits for the lock. Now you have thread B and D both waiting.
  • Thread C releases the lock. Even through thread B has been waiting the longest, the lock is arbitrarily given to thread D.

And so it continues until the WCF call times out, and you get an impossible-to-reproduce error.

If I had to implement this, I would have a single worker thread dedicated to generating the PDF files. This thread would be launched when the service first starts up, and it waits to pick up a job off a job queue. Each WCF query will place a request on this queue, and there will be some way it can block until it knows the job has been processed.

.NET 4.0 provides the BlockingCollection class to help with this. (See this question)

This gives you the approach without a complete solution because it isn't a trivial problem. Good luck!

like image 103
Andrew Shepherd Avatar answered Sep 28 '22 18:09

Andrew Shepherd


WCF supports synchronized calling of your service objects, depending on your needs, you may want to look into the following two properties:

  • ServiceBehavior.InstanceContextMode: http://msdn.microsoft.com/en-us/library/system.servicemodel.servicebehaviorattribute.instancecontextmode.aspx
  • ServiceBehavior.ConcurrencyMode: http://msdn.microsoft.com/en-us/library/system.servicemodel.servicebehaviorattribute.concurrencymode.aspx

If you cannot launch multiple instances of 3rd party component, and the component does not allow concurrent acccess (the worst case), then you can specify InstanceContextMode = Single, and ConcurrencyMode = Single; In this case, WCF will only instantiate a single copy of your WCF object (which I assume is a wrapper around 3rd party component), and only one request is processed at a time. The requests will be queued up and processed in a FIFO manner. You don't have to use lock inside your wcf service, since the WCF runtime makes sure you have synchronized access to your wcf objects.

like image 43
X.J Avatar answered Sep 28 '22 20:09

X.J