Skip to content

Excessive "HttpMessageHandler cleanup cycle" Logs in Long-Running Service Injecting ISendGridClient #1213

@sdepouw

Description

@sdepouw

I have a Windows Service written in .NET 8 that uses C# classes, some of which use Dependency Injection (the AddSendGrid() extension) to get an instance of ISendGridClient. It seems that when using this in a Windows service, or otherwise a C# class that's loaded once and remains active for the entire application's runtime (basically think of it being used in a Singleton), our application logs are flooded with messages like this (note InjectableSendGridClient:

[07:14:06 DBG] Hosting started
[07:16:06 DBG] HttpMessageHandler expired after 120000ms for client 'InjectableSendGridClient'
[07:16:16 DBG] Starting HttpMessageHandler cleanup cycle with 1 items
[07:16:16 DBG] Ending HttpMessageHandler cleanup cycle after 0.0233ms - processed: 0 items - remaining: 1 items
[07:16:26 DBG] Starting HttpMessageHandler cleanup cycle with 1 items
[07:16:26 DBG] Ending HttpMessageHandler cleanup cycle after 0.0061ms - processed: 0 items - remaining: 1 items
[07:16:36 DBG] Starting HttpMessageHandler cleanup cycle with 1 items
[07:16:36 DBG] Ending HttpMessageHandler cleanup cycle after 0.0032ms - processed: 0 items - remaining: 1 items
[07:16:46 DBG] Starting HttpMessageHandler cleanup cycle with 1 items
[07:16:46 DBG] Ending HttpMessageHandler cleanup cycle after 0.0035ms - processed: 0 items - remaining: 1 items
[07:16:56 DBG] Starting HttpMessageHandler cleanup cycle with 1 items
[07:16:56 DBG] Ending HttpMessageHandler cleanup cycle after 0.0034ms - processed: 0 items - remaining: 1 items
[07:17:06 DBG] Starting HttpMessageHandler cleanup cycle with 1 items
[07:17:06 DBG] Ending HttpMessageHandler cleanup cycle after 0.006ms - processed: 0 items - remaining: 1 items
[07:17:16 DBG] Starting HttpMessageHandler cleanup cycle with 1 items

As you can see, after the given class is alive for 2 minutes, the cleanup cycle runs every 10 seconds after the fact. It appears that ISendGridClient is keeping a single HttpClient instance alive for the entire duration the ISendGridClient remains in scope.

Is there a way to use ISendGridClient in a disposable context? Something like using(ISendGridClient client = someFactory.CreateClient())? Or, would it be possible that, when injecting ISendGridClient via dependency injection (i.e. constructor injection) for it to manage its internal client so it isn't "kept alive" for long-running services/processes? Some way to support using ISendGridClient in singleton/long-running scenarios?

Note that I cannot simply "turn off logging at the Debug level" in this scenario.

Here's how we're setting up dependency injection in Program.cs:

using Microsoft.Extensions.Hosting;
using SendGrid.Extensions.DependencyInjection;

HostApplicationBuilder builder = Host.CreateApplicationBuilder();

builder.Services.AddSendGrid(opts => opts.ApiKey = "my-api-key");

Here's how we're using the class:

using SendGrid;

public class SendGridEmailService(ILogger<SendGridEmailService> logger, ISendGridClient client)
{
  // ISendGridClient used in this class
}

Current Workaround

Presently my only idea is to inject IServiceProvider instead, then get the client at runtime.

public class SendGridEmailService(ILogger<SendGridEmailService> logger, ISerivceProvider provider)
{
  public async Task SendMailAsync(SendGridMessage message, CancellationToken cancellationToken)
  {
    ISendGridClient sendGridClient = provider.GetRequiredService<ISendGridClient>();
    await sendGridClient.SendEmailAsync(message, cancellationToken);
  }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions