HttpClient best practices in Azure Functions
Solution 1
Yes - this is still the current guidance for Azure Functions 1.x (and applies to 2.x as well) to best avoid socket exhaustion. The static variable will ensures that it will be shared against all instances of the class. Another good article that covers this topic is https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong
Solution 2
As of 2019, and v2/v3+ of the runtime, you also have the option to use dependency injection in .NET Azure Functions. Be aware that this only applies to .NET functions (C#), and AFAIK is not available for the other flavours, like Python, JavaScript/TypeScript etc.
Simple answer is that you can add a Startup.cs class to your Azure Function where your register the dependencies:
[assembly: FunctionsStartup(typeof(MyInjectedFunction.Startup))]
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
// Note: Only register dependencies, do not depend or request those in Configure().
// Dependencies are only usable during function execution, not before (like here).
builder.Services.AddHttpClient();
// builder.Services.AddSingleton<ILoggerProvider, MyLoggerProvider>();
}
}
Pretty much the same as any other web/api project with dotnet core. Next, in your function itself, add a constructor and register the dependencies as parameters. You also want to remove the static
modifier from your function. An example:
public class MyInjectedFunction
{
private readonly HttpClient _http;
public MyInjectedFunction(HttpClient httpClient)
{
_http = httpClient;
}
[FunctionName("my-injected-function")]
public async Task RunAsync([EventGridTrigger] EventGridEvent eventGridEvent, ILogger log)
{
var response = await _http.GetAsync("https://stackoverflow.com");
if (response.IsSuccessStatusCode)
log.LogInformation("Okidoki");
else
log.LogError($"{response.StatusCode} {response.ReasonPhrase}: ");
}
}
By using DI you can explicitly register it as singleton as well. Or created typed HttpClients. And personally, I think this is quite elegant.
RPM1984
~ Past ~: Mainframes (Model 204, JCL) Java (J2SE, J2EE) Oracle VB.NET ASP.NET Web Forms/MVC ~ Present ~ .NET Core TDD, DDD (all the DDs!) Microservices Containers
Updated on July 22, 2022Comments
-
RPM1984 almost 2 years
I need to build an Azure Function that:
- Responds to a
HTTP POST
request - Does 7x
HTTP HEAD
requests based on the data.
I've found some guidance here and here
But, it's not entirely clear what to do, and how it works?
As in the second link, i've currently just declared a
private static HttpClient httpClient = new HttpClient();
instance, and re-used that in my 7x HTTP HEAD calls.My questions:
- Is that the most efficient use of
HttpClient
in a stateless Azure function? - I'm currently just building up a
List<Task>()
for the http calls, then doingTask.WhenAll(tasks)
on them to run them in parrallel. Would that be the quickest way to do these calls? Any other suggestions?
This Function endpoint will be called a lot (multiple times a second), so need to be as efficient as possible to keep costs down.
Thanks!
- Responds to a
-
RPM1984 almost 6 yearsThanks. That article is 2016 though? Is there nothing more recent showing it's still the best way? Not doubting you, just want to make sure :)
-
Josh Carlisle almost 6 yearsAt least in regards to 1.x of Azure Functions and the .net framework 4.x not a lot has changed that would affect the guidance since 2016 :) Azure Functions 2.x though may bring in some new options\best practices since it sits on .net core 2.1 . I suspect the guidance will largely be the same (maximize reuse) but there is some new httpclient related constructs such as HttpClientFactory (stevejgordon.co.uk/introduction-to-httpclientfactory-aspnetcore) that may introduce some new or additional options\guidance.
-
Zordid over 5 yearsThis solution really is NOT a correct usage of HttpClient in general. Holding one instance is also wrong als DNS changes don't get through. You will eventually lose all connectivity. That's why there is HttpClientFactory - but only in ASP .Net Core 2.1. My question now is: what should we do now?
-
Zhaph - Ben Duguid almost 5 years@RPM1984 - Official documentation from Microsoft on this can be found here. However as Zordid mentions, if you can use the newer HttpClientFactory that's better.
-
HisDivineShadow over 3 yearsI read this in the Azure docs but it's not clear about how it's creating the HttpClient in the function. Apparently Azure functions have a host DI container that is "holding" every requested instance of the function and providing the HttpClient as a singleton to ALL function instances and therefore you cannot change the BaseUri after the first time it's been configured. So, if it's in fact a singleton and can't be modified then where is the appropriate place to configure the HttpClient?