3

I have a WCF service which accepts requests and for each request makes an HTTPWebRequest call and returns the response. I use a BlockingCollection to store the requests as they come in and a separate thread processes (makes the webrequest) the items in the collection. Sometimes the Webrequest returns a threadabortexception. I catch it and do a Thread.ResetAbort. But the exception flows up and and it clears the BlockingCollection. I have added snippets of the code below. I need to find a way for the foreach loop to keep continuing even if i get a threadabort exception.

public static class YBProcessor
{
    static PriorityQueue<QueuePriorityLevel, string> queue = new PriorityQueue<QueuePriorityLevel, string>();
    static BlockingCollection<KeyValuePair<QueuePriorityLevel, string>> requests;
    static YBProcessor()
    {        
        requests = new BlockingCollection<KeyValuePair<QueuePriorityLevel, string>>(queue);
        Task.Factory.StartNew(() => SendRequestToYB());
    }
    public static void AddCalcRequest(string cusip, double price, QueuePriorityLevel priority)
    {
         requests.Add(new KeyValuePair<QueuePriorityLevel, string>(priority, cusip + "-" + price.ToString()));                                          
    }
   private static void SendRequestToYB()
   {
       // this is a separate thread that processes the requests as the come in.
      foreach (var obj in requests.GetConsumingEnumerable())
      {                 
          try
          {
            var request = GetXML(obj.Value);
            var response = YBClient.GetResponse(request);
            //code to handle response
          }
          catch (ThreadAbortException ex)
          {
            Thread.ResetAbort();
          }
          catch (Exception ex)
          {
          }
       }    
     }
}

// In YBClient The GetResponse Method (just the key parts. Code wont compile)

private static String GetResponse(String text)
{
    for (iTry = 0; iTry < MAX_TRY; iTry++)
    {

        try
        {
            // Create and setup request
            bytes = encoding.GetBytes(text);
            request = (HttpWebRequest)WebRequest.Create(uri);
            request.Method = "POST";
            request.ContentType = "text/xml";
            request.ContentLength = bytes.Length;
            request.CookieContainer = cookieJar;
            request.Timeout = 100 * 1000;
            request.ReadWriteTimeout = 100 * 1000;

            // Prepare and send data
            postStream = request.GetRequestStream();
            postStream.Write(bytes, 0, bytes.Length);
            postStream.Close();

            // Get response from server
            response = (HttpWebResponse)request.GetResponse();
            if (response.StatusCode == HttpStatusCode.OK)
            {
                reader = new StreamReader(response.GetResponseStream(), encoding);
                xmlResponse = reader.ReadToEnd();
                reader.Close();
                break;
            }               
            response.Close();
        }
        catch (ThreadAbortException ex)
        {
            Thread.ResetAbort();                
            break;              
        }           
        catch (Exception ex)
        {               
            if (ex.GetBaseException() is ThreadAbortException)
            {                   
                Thread.ResetAbort();
                break;
            }
        }
    }       
}
return xmlResponse;
}
Satfactor
  • 379
  • 1
  • 3
  • 20

1 Answers1

1

If the service itself is calling the thread abort exception then it might mean the service is going down, in that scenario your thread cannot continue to function (imagine a app pool recycle), If you want to make sure your pending requests are not lost then you can do one of the following:

1) Start a new appdomain http://msdn.microsoft.com/en-us/library/ms173139(v=vs.90).aspx

This method will mitigate service shutting down, however will still not resolve the fundamental issue of making sure all your requests are processed as the "other" app domain can also go down.

2) The better solution will be to keep writing your requests in serialized form in a central DB or a file and get a worker to keep popping items out of the same, if you want simplicity, create seperate files for each requests and delete them once processed (assuming you wont get thousands of requests/sec), for a more scalable solutions you can use Redis database (http://redis.io/) and use its "list" (queue) functionality.

P.S. You might want to mark your thread (task) as long running, if you don't, it uses the thread pool which is not recommended for very long running tasks.

 Task.Factory.StartNew(Run, TaskCreationOptions.LongRunning);
Sumit Maingi
  • 2,173
  • 3
  • 24
  • 44