tags:

views:

56

answers:

2

If a WCF Service gets the same request, means the same MD5 over all Parameters i want to block all except the first request until the processing is done and notify all waiting clients.

What is the best way doing this? I thaugh of something like a channel sink, maybe there is a finnished implementation for archieving this?

A: 

At first, I am thinking of a custom implementation for a hashtable to keep the MD%'s being processed and lookup for the same before starting a new request processing.

Kangkan
yes. this is logical. the problem i am interested in is how to efficent block the threads and which event to hook. Maybe there is a smart way which fits perfectly into the WCF architecture.
Snoopy
+1  A: 

I'm not sure about what would be the 'best' fit for the WCF architecture but you should consider setting your InstanceContextMode to Single as you're likely to be doing a lot of synchronization steps for what you want to do here.

How about something like this? You will obviously need to do some synchronization on the dictionary itself, but at least it's a start.

private IDictionary<string, RequestToken> RequestTokens = 
   new Dictionary<string, RequestToken>();

public MyResponse MyMethod(MyRequest request)
{
   // get the MD5 for the request
   var md5 = GetMD5Hash(request);

   // check if another thread is processing/has processed an identical request
   RequestToken token;
   if (RequestTokens.TryGetValue(md5, out token))
   {
      // if the token exists already then wait till we can acquire the lock
      // which indicates the processing has finished and a response is ready
      // for us to reuse
      lock (token.Sync)
      {
         return token.Response;
      }
   }
   else
   {
      var token = new Token(md5);
      lock (token.Sync)
      {
         RequestTokens.Add(md5, token);

         // do processing here..
         var response = ....

         token.Response = response;

         return response;
      }
   }
}

private class RequestToken
{
   private readonly object _sync = new object();

   public RequestToken(string md5)
   {
      MD5 = md5;
   }

   public string MD5 { get; private set; }

   public object Sync { get { return _sync; } }

   public MyResponse Response { get; set; }
}

To me, this is something I'd want to abstract away from my business logic, and I'll personally use PostSharp and write a little attribute to handle all this.

I've written a Memoizer attribute which does something similar in the lines of caching responses based on request but without the synchronization steps, so you could probably take a look at what I've done and modify it accordingly to achieve what you're after.

theburningmonk
this is the simplest approach which for sure works. But this is exactly what i wanted to prevent. I am seeking for something high efficent able to handle 1000 or more requests a second.
Snoopy
Do you really need to block all subsequent requests with the same MD5 checksum until the first request is done? That kinda synchronization will obviously have an impact on how much concurrency you can push through your service.Also, you will most likely need to scale out across multiple machines to be able to handle 1000+ requests a second, esp if your operations are expensive. And to do what you're trying to do across machines is another beast all together!
theburningmonk
i dont want to block across machines. this is inefficent i think. i know that multiple calls (>100) hit me concurrently due a bad designed third party system which calls my service.
Snoopy