microsoft / PowerPlatform-DataverseServiceClient

Code Replica for Microsoft.PowerPlatform.Dataverse.Client and supporting nuget packages.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

ServiceClient.Clone() uses more connections than expected

FarmerenHE opened this issue · comments

Hi, a potential issue with how Clone() works in 1.1.16

Were using some old .Net Framework code that have been upgraded to .Net 6 with as few changes as possible, due to how parallel code works in .Net Framework all our calls to the serviceclient are wraped in code like

Using Clone = _staticServiceClient.Clone();
Clone.Execute(Message);

When running the above on Consumption based Azure Functions the function host very quickly reaches 600 active connections (upper limit) and throws the following error. An exception was thrown by the invocation.
Exception: System.AggregateException: One or more errors occurred. (An attempt was made to access a socket in a way forbidden by its access permissions. (xxx.crm4.dynamics.com:443))

This error occurs no matter if the "useUniqueInstance" flag is set to true or false.

As far as we can tell it dosen't share the HTTP connection but open up its own connection (it retrys the call inside the HTTP client and eventually gets a connection to call dataverse).

As the new recommended approach is to not use clones in .Net 6 we have changed the code and it works as intended without clones (sharing the HTTP Connectionpool).

As were moving all our code away from .Net Framework we have not tested to see if the same issue is also present when running on .Net Framework.

@FarmerenHE ,
.net core ( specifically .net 6 ) introduces some pretty drastic changes in how multithreading and networking work under the covers. 95% of these are very good, long needed, things that improve performance and such. 5% of them cause some challenges, but that is the cost of moving the development frameworks and setting aside older tech that has been significantly superseded by newer concepts.

I would strongly encourage you to move to using the Async methods as quickly as possible.

That said, the behavior you're seeing with .clone is a byproduct of changes made to how garbage collection works in .net core+. We have seen this a few where our internal teams updated to .net core. When you create a clone, as you have seen, a totally new connection is created using a local httpclient. It is very important that you explicitly call dispose on the cloned connection when your done with it, then null the pointer to make sure .net core will dispose it and allow the port to release. .net framework was much more aggressive about cleaning up released objects that had not been explicitly disposed.

In the Dataverse ServcieClient from 1.1.10 + UseUniqueInstance is unwired and does not perform a function. All of the connection caching code that was a part of that system has been removed or deactivated.

We found the issue as we changed to doing Async, should I take it as we should avoid the non async method entirely? Because then I'm going to mark them as obsolete in our own extension on the IOrgservice to nudge everyone to make sure they use the async version.

Are any of the 4 recommendations in https://learn.microsoft.com/en-us/power-apps/developer/data-platform/send-parallel-requests?tabs=sdk#optimize-your-connection stil relevant? Or can those be ignored as legacy .Net Framework as well?

@FarmerenHE in the article you reference, you will notice there is .net 6+ section and a .net framework section and they are different. This is, as I said above, a byproduct of the significant changes made in .net 6+

The recommendations are correct and tested for each.

Insofar as guiding using Async in your external clients directly, Yes, that is what we are encouraging strongly :)

thanks.