0

I have .NET Core 3.1 Web API in a docker container on Linux.

I use test tool that makes 1000 sequential requests to the Web API.

The Web API controller looks like this:

    public MyController(ISendService sservice)
    {
        _sservice = sservice;
    }


    [HttpPost()]
    public async Task<IActionResult>  SendMessage([FromBody] SendMessageRequest request)
    {
            await _sservice.SendIt(request.Message);
    }

My Send Service looks like this:

    public class SendService: ISendService
    {
       private readonly HttpClient _client;

       public SendService(HttpClient client)
       {
           _client = client;
       }

       public async Task SendMessage(string data)
       {
          var request= new HttpRequestMessage(HttpMethod.Post, "https://somelocation/test") { Version = new Version(2, 0) };

          request.Content = new StringContent(data);

          var response = await _client.SendAsync(request);
           
         //Log response
       }
    }

I add the SendService in Startup like so:

        services.AddHttpClient<ISendService, SendService>().ConfigurePrimaryHttpMessageHandler(() =>
        {
            var handler = new HttpClientHandler { SslProtocols = SslProtocols.Tls12 };
            var store = new Store.GetStore();
            handler.ClientCertificates.Add(store.certificate);
            return handler;
        });

My problem is that whenever SendMessage is called, the memory usage inside docker container goes up with each request. i.e. I call it 10 times, the memory will go up and stay there. I call it 1000 times, the memory goes up and up, beyond 85% (read that the limit should be 75% in .NET Core 3.1) and stay there even waiting 20 minutes with each test scenario.

Why does it not appear to garbage collect or release the memory? I running tests but I think it will reach 100% and the service will stop which is not good. Thank you

PKCS12
  • 407
  • 15
  • 41
  • The connections may not be closing. Try from cmd.exe >Netstat -A and see if you have more than one connection. – jdweng Jul 23 '20 at 15:53

1 Answers1

-1

Right now you are blocking on every call to your service by doing

_client.SendAsync(request).GetAwaiter().GetResult()

and thats a big no-no. You can read more about it here: https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

Change your ISendService interface from

void SendMessage(string data)

to

Task SendMessage(string data)

Then in your SendService add async in your method declaration and replace the following row

var response = _client.SendAsync(request).GetAwaiter().GetResult();

With

var response = await _client.SendAsync(request);

Then in your controller add the async keyword and await it like this:

[HttpPost()]
public async Task<IActionResult> SendMessage([FromBody] SendMessageRequest request)
{
        await _sservice.SendIt(request.Message);
}

Also, regarding the memory usage, are you sure that it's an issue? Unused memory is worthless... :)

JOSEFtw
  • 9,781
  • 9
  • 49
  • 67
  • Thanks a lot for your time. I tried as you suggest and am running another test (See my updated question above). The intial test (with docker container limited to 40M memory) unfortunately showed the same results. I am trying with 60M. – PKCS12 Jul 23 '20 at 17:11
  • You can find more information regarding memory usage here: https://stackoverflow.com/questions/57591344/why-asp-net-core-2-2-do-not-release-memory – JOSEFtw Jul 23 '20 at 17:18
  • 1
    Note that I don't recommend the accepted answer to that question. I would just try to raise the amount of ram and then let dotnet handle the GC :) – JOSEFtw Jul 23 '20 at 17:20
  • Of course unused memory is worthless, that's precisely it is an issue. GC does not collect everything, specifically objects which have a valid (static or global) reference and are not disposed/handled by the code. Typed clients are added as transient services but reuse HttpMessageHandlers under the hood. Perhaps creating a new handler is causing the memory issue. – Abubakar Mehmood Dec 01 '20 at 16:14