Search code examples
c#asp.nethttpwebrequestsemaphorethrottling

Avoid network throttling when making HTTP requests


I have a very specific problem when making HTTP webrequests. To be more specific, the application is making the requests 24/7 and updating my database table. Since other users are performing requests as well, I've came into a situation where when I make parallel web requests using parallel for loop with a combination of concurrent bag to speed things up, the other users experience a huge slowdown in websites performance. At some point the website becomes very slow and unresponsive when users + application makes the requests... So now my question is following:

How can I limit the applications amount of webrequests it does at a specific moment?

For example if there are 10000 ports available through which app can make a web request. I wanna be able to tell to application to use lets say 10/15 threads at a time to make the request, and at the same time not to slow down the website to user so that there is no network throttling.

I read a few articles and some people were suggesting to use semaphore slim, but I have no idea how can I pair it up with my web request which looks like following:

  private string MakeHTTPWebRequest(string requestXML)
        {
            var request = (HttpWebRequest)WebRequest.Create("https://api.ebay.com/ws/api.dll");
            string GetItemTransactionXMLRequest = null;
            byte[] bytes = null;
            bytes = System.Text.Encoding.ASCII.GetBytes(requestXML);
            ServicePointManager.DefaultConnectionLimit = 9999;
            ServicePointManager.Expect100Continue = false;
            request.Method = "POST";
            request.ContentType = "application/xml";
            request.Accept = "application/xml";
            request.Proxy = null;

            Stream requestStream = request.GetRequestStream();
            requestStream.Write(bytes, 0, bytes.Length);
            requestStream.Close();
            using (var response = (HttpWebResponse)request.GetResponse())
            {
                if (response.StatusCode == HttpStatusCode.OK)
                {
                    Stream responseStream = response.GetResponseStream();
                    string responseStr = new StreamReader(responseStream).ReadToEnd();
                    responseStream.Flush();
                    responseStream.Close();
                    return responseStr;
                }
                return null;
            }
        }

This is how I do it currently:

Parallel.For(0,somelength,i=> List.Add(MakeHTTPWebRequest("Some xml request here")));

The method above gives me terrible network throttling. How can I do this in a manner where application would know if it's causing network throttling to reduce number of calls or await while user makes the request and then it continues the request?

At the same time this raises another question and issue, how can I set the timeout in this webrequest to unlimted xxx minutes so that app can wait till others are done with their requests so it can continue fetching the results from API...

Can someone help me out with this ?


Solution

  • You're setting some global variables every time you make an HTTP request. I'd recommend only setting them once.

    I wanna be able to tell to application to use lets say 10/15 threads at a time to make the request

    The fastest fix would be to just pass a ParallelOptions parameter to Parallel.For, setting MaxDegreeOfParallelism to 10/15.

    I would also recommend considering making the code asynchronous, since this is an I/O-bound operation. That's where you would use SemaphoreSlim for throttling.

    How can I do this in a manner where application would know if it's causing network throttling to reduce number of calls

    That's a much harder problem. You'd have to measure your response times and feed them into a routine that establishes a "normal response time", and then starts throttling if the response times start getting too big. This is assuming that your app is throttled similarly to how a user would be.