Azure-functions-host: DI-related instability when using HttpClientFactory

Created on 4 Feb 2020  路  5Comments  路  Source: Azure/azure-functions-host

Investigative information

  • Timestamp: February 3rd, 2020, ~5:40PM CST
  • Function App version: ~3, Runtime version: 3.0.13107
  • Function App name: (will provide if needed)
  • Function name(s) (as appropriate): (will provide if needed)
  • Invocation ID: (will provide if needed)
  • Region: Central US

Repro steps

I'm referencing the following nuget packages:

  <ItemGroup>
    <PackageReference Include="Microsoft.Azure.Functions.Extensions" Version="1.0.0" />
    <PackageReference Include="Microsoft.Data.SqlClient" Version="1.1.0" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.1">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.1" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.1">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
    <PackageReference Include="Microsoft.Extensions.Http" Version="3.1.1" />
    <PackageReference Include="Microsoft.NET.Sdk.Functions" Version="3.0.3" />
  </ItemGroup>

I'm using Microsoft.Azure.Functions.Extensions for DI like so:

    public class Startup : FunctionsStartup
    {
        public override void Configure(IFunctionsHostBuilder builder)
        {
            builder.Services.AddHttpClient();
            builder.Services.AddScoped<IApiService, ApiService>();
        }
    }

And the service looks something like this:

    public class ApiService : IApiService
    {
        private readonly IHttpClientFactory _httpClientFactory;

        public ApiService(IHttpClientFactory httpClientFactory)
        {
            _httpClientFactory = httpClientFactory;
        }

        public void MakeRequest()
        {
            var httpClient = _httpClientFactory.CreateClient();
            httpClient.PostAsync(...);
        }
    }

And the function looks something like this:

    public class MyTrigger
    {
        private readonly IApiService _apiService;

        public MyTrigger(IApiService apiService)
        {
            _apiService = apiService;
        }

        [FunctionName("MyTrigger")]
        public void Run([TimerTrigger("0 */5 * * * *", RunOnStartup = true)]TimerInfo timerInfo, CancellationToken cancellationToken)
        {
            foreach (var x in alot)
            {
                _apiService.MakeRequest();
            }
        }
    }

Here's the error message and stack trace I see in App Insights:

Scope disposed{no name, Parent=disposed{no name, Parent={no name, Parent={no name}}}} is disposed and scoped instances are disposed and no longer available.

DryIoc.ContainerException:
   at DryIoc.Throw.It (Microsoft.Azure.WebJobs.Script.WebHost, Version=3.0.0.0, Culture=neutral, PublicKeyToken=nullMicrosoft.Azure.WebJobs.Script.WebHost, Version=3.0.0.0, Culture=neutral, PublicKeyToken=null: D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\DryIoc\Container.csMicrosoft.Azure.WebJobs.Script.WebHost, Version=3.0.0.0, Culture=neutral, PublicKeyToken=null: 8990)
   at DryIoc.Scope.TryGet (Microsoft.Azure.WebJobs.Script.WebHost, Version=3.0.0.0, Culture=neutral, PublicKeyToken=nullMicrosoft.Azure.WebJobs.Script.WebHost, Version=3.0.0.0, Culture=neutral, PublicKeyToken=null: D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\DryIoc\Container.csMicrosoft.Azure.WebJobs.Script.WebHost, Version=3.0.0.0, Culture=neutral, PublicKeyToken=null: 7880)
   at DryIoc.Container+InstanceFactory.GetAndUnwrapOrDefault (Microsoft.Azure.WebJobs.Script.WebHost, Version=3.0.0.0, Culture=neutral, PublicKeyToken=nullMicrosoft.Azure.WebJobs.Script.WebHost, Version=3.0.0.0, Culture=neutral, PublicKeyToken=null: D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\DryIoc\Container.csMicrosoft.Azure.WebJobs.Script.WebHost, Version=3.0.0.0, Culture=neutral, PublicKeyToken=null: 1479)
   at DryIoc.Container+InstanceFactory.GetInstanceFromScopeChainOrSingletons (Microsoft.Azure.WebJobs.Script.WebHost, Version=3.0.0.0, Culture=neutral, PublicKeyToken=nullMicrosoft.Azure.WebJobs.Script.WebHost, Version=3.0.0.0, Culture=neutral, PublicKeyToken=null: D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\DryIoc\Container.csMicrosoft.Azure.WebJobs.Script.WebHost, Version=3.0.0.0, Culture=neutral, PublicKeyToken=null: 1465)
   at DryIoc.Container.DryIoc.IResolver.Resolve (Microsoft.Azure.WebJobs.Script.WebHost, Version=3.0.0.0, Culture=neutral, PublicKeyToken=nullMicrosoft.Azure.WebJobs.Script.WebHost, Version=3.0.0.0, Culture=neutral, PublicKeyToken=null: D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\DryIoc\Container.csMicrosoft.Azure.WebJobs.Script.WebHost, Version=3.0.0.0, Culture=neutral, PublicKeyToken=null: 307)
   at lambda_method (Anonymously Hosted DynamicMethods Assembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null)
   at DryIoc.Container.ResolveAndCacheDefaultFactoryDelegate (Microsoft.Azure.WebJobs.Script.WebHost, Version=3.0.0.0, Culture=neutral, PublicKeyToken=nullMicrosoft.Azure.WebJobs.Script.WebHost, Version=3.0.0.0, Culture=neutral, PublicKeyToken=null: D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\DryIoc\Container.csMicrosoft.Azure.WebJobs.Script.WebHost, Version=3.0.0.0, Culture=neutral, PublicKeyToken=null: 223)
   at DryIoc.Container.DryIoc.IResolver.Resolve (Microsoft.Azure.WebJobs.Script.WebHost, Version=3.0.0.0, Culture=neutral, PublicKeyToken=nullMicrosoft.Azure.WebJobs.Script.WebHost, Version=3.0.0.0, Culture=neutral, PublicKeyToken=null: D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\DryIoc\Container.csMicrosoft.Azure.WebJobs.Script.WebHost, Version=3.0.0.0, Culture=neutral, PublicKeyToken=null: 194)
   at Microsoft.Azure.WebJobs.Script.WebHost.DependencyInjection.ScopedServiceProvider.GetService (Microsoft.Azure.WebJobs.Script.WebHost, Version=3.0.0.0, Culture=neutral, PublicKeyToken=nullMicrosoft.Azure.WebJobs.Script.WebHost, Version=3.0.0.0, Culture=neutral, PublicKeyToken=null: D:\a\1\s\src\WebJobs.Script.WebHost\DependencyInjection\ScopedServiceProvider.csMicrosoft.Azure.WebJobs.Script.WebHost, Version=3.0.0.0, Culture=neutral, PublicKeyToken=null: 25)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService (Microsoft.Extensions.DependencyInjection.Abstractions, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService (Microsoft.Extensions.DependencyInjection.Abstractions, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60)
   at Microsoft.Extensions.Http.DefaultHttpClientFactory.CreateHandlerEntry (Microsoft.Extensions.Http, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60)
   at Microsoft.Extensions.Http.DefaultHttpClientFactory+<>c__DisplayClass14_0.<.ctor>b__1 (Microsoft.Extensions.Http, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60)
   at System.Lazy`1.ViaFactory (System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e)
   at System.Lazy`1.ExecutionAndPublication (System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e)
   at System.Lazy`1.CreateValue (System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e)
   at System.Lazy`1.get_Value (System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e)
   at Microsoft.Extensions.Http.DefaultHttpClientFactory.CreateHandler (Microsoft.Extensions.Http, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60)
   at Microsoft.Extensions.Http.DefaultHttpClientFactory.CreateClient (Microsoft.Extensions.Http, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60)
   at System.Net.Http.HttpClientFactoryExtensions.CreateClient (Microsoft.Extensions.Http, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60)

Expected behavior

I expect HttpClientFactory to be supported and stable for Azure Functions v3.

Actual behavior

It went well for a good 1k+ requests, but eventually it bombed out with essentially the same error as seen in #5060. Unlike that issue however, I'm injecting HttpClientFactory instead of HttpClient like was recommended in the comments and calling factory.CreateClient() each time a request needs to be made. Looks like #5074 may have been a reproduction of this as well. Is there something else I should be doing in the code to avoid this bizarre issue?

Known workarounds

I switched back to the old school approach of a static HttpClient and that works well enough for my needs, but I'm assuming HttpClientFactory is the way of the future.

needs-investigation

Most helpful comment

Any update on this? There are numerous issues which are the same as this one, a couple I found with a quick search:

https://github.com/Azure/azure-functions-host/issues/5851
https://github.com/Azure/azure-functions-host/issues/6087

6 months of DI issues for something as fundamental as a Http Client without an official word on the subject isn't great, could someone at least respond?

All 5 comments

cc: @fabiocav

Any update on this? There are numerous issues which are the same as this one, a couple I found with a quick search:

https://github.com/Azure/azure-functions-host/issues/5851
https://github.com/Azure/azure-functions-host/issues/6087

6 months of DI issues for something as fundamental as a Http Client without an official word on the subject isn't great, could someone at least respond?

Do we have an update on this. I am also facing this weird issue.

Anyone here in this tread, looking into this with Priority. Its like a dead end. Not sure what is to be done to solve this annoying and weird issue.
Is there any connection with having async call ? My first async call works fine, then the next call to the same object fails, where its again trying to get the service using
using (var scope = _serviceScopeFactory.CreateScope())
{
return (T)scope.ServiceProvider.GetRequiredService(typeof(T));
}
This statement : (T)scope.ServiceProvider.GetRequiredService(typeof(T)); gives the following error.
Scope disposed{no name} is disposed and scoped instances are disposed and no longer available

Was this page helpful?
0 / 5 - 0 ratings