Reputation: 77
I have a REST service that calls another REST service. Both are using MVC 4 WebAPI and calling them works fine until I put it under a load. The simplified code is something like:
public HttpResponseMessage Get()
{
var url = WebHelpers.CreateUrl(Request, "EmployeesGet");
var client = new HttpClient();
var response = client.GetAsync(url).Result;
var retResp = new HttpResponseMessage();
retResp.Content = response.Content;
return retResp;
}
The WebHelper.CreateUrl
constructs the endpoint url.
When I put a load on, 100 users simulated, I get to about 16,000 requests and I get a socket exception:
SocketException An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full
This takes the network stack of my pc down until I reset IIS.
I thought perhaps I need to be more proactive on cleaning up so I disposed of the HttpClient
with no effect. Then I thought I need to Dispose the response I got from the endpoint since once I get the content I don't need it anymore. Strange thing is that I then get an exception that says a disposed object can't be referenced. This is coming from the MVC framework. Exception follows:
[ObjectDisposedException: Cannot access a disposed object. Object name: 'System.Net.Http.StreamContent'.] System.Web.Http.WebHost.HttpControllerHandler.EndProcessRequest(IAsyncResult result) +49019 System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +469 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +375
If I return a stream or just the content things work fine, but then I can't change the response's status code or add any other meta data to the response.
So what would be the best way to return a response from a Get method that has received the content from another call to a REST service. I don't want to deserialize/serialize and I would really like to be able to add some data to the response going out.
Update: While looking at the Resource Monitor while doing the load test, I see the connections stacking up. It seems, and I can't say for sure, but it seems the call to the endpoint from inside the Get()
is not releasing the connection.
Upvotes: 3
Views: 5048
Reputation: 142222
I would suggest trying to inject into the controller a pre-created HttpClient instance and re-using it across requests. When a HttpClient is disposed it goes off and attempts to close the underlying connection. From what I recall of looking at the HttpClient source, you will be opening a new connection every time you create a new HttpClient instance.
Upvotes: 2
Reputation: 53183
A couple of things
.Result
which will block a thread. That might be part of your performance problem. Because you are performing an async operation you should make your action method be async by returning Task<HttpResponseMessage>
and schedule a continuation that will convert the result of your inner service call into the body of the outer call.HttpContent
of the inner call into the result of the outer call. You might want to try reading the inner stream and copying it into a new outer stream.Upvotes: 1