Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

BackgroundService not shutting down, stoppingToken never set with .net core generic host

I have a BackgroundService hosted in .net generic host as follows:

var builder = Host.CreateDefaultBuilder(args);

builder
    .ConfigureLogging((hostingContext, logging) =>
    {
        logging.ClearProviders();
        logging.AddConsole();
        if(hostingContext.HostingEnvironment.IsDevelopment() == true)
            logging.AddDebug();
    })
    .ConfigureHostConfiguration(configurationBuilder =>
    {
        configurationBuilder.AddCommandLine(args);
    })
    .ConfigureAppConfiguration((hostingContext, configApp) =>
    {
        var env = hostingContext.HostingEnvironment;
        Console.WriteLine(env.EnvironmentName);
    })
    .UseConsoleLifetime();

I then have my worker:

public class Worker : BackgroundService
{
    private readonly ILogger<Worker> _logger;

    public Worker(ILogger<Worker> logger)
    {
        _logger = logger;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        // here i am doing something with ClientWebSocket, threads etc
        // snipped for brevity. I want to avoid spinning in a loop

        // the debugger reaches the following line
        WaitHandle.WaitAny(new[] { stoppingToken.WaitHandle });

        // but never hits this line
        this.logger.LogInformation("shutting down worker");
    }
}

On ctrl+c from the windows terminal of the running app it says Application is shutting down (this is from the framework) however the stoppingToken never gets set (so i cant shutdown my worker).

How and when does stoppingToken get set, and how can i gracefully terminate my worker?

The console

like image 706
morleyc Avatar asked Oct 17 '25 11:10

morleyc


1 Answers

For BackgroundServices, they need to continue running until the cancellation token says to stop. To do that, you need a while loop. However, when you pass this cancellation token into any Async method, it will stop that method from running all the way through the chain if you use that same token in all the layers. It should look something like this:

  protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            // here i am doing something with ClientWebSocket, threads etc
            // snipped for brevity. I want to avoid spinning in a loop
            ... 
            await client.DownloadAsync(..., stoppingToken);
            ...
        }

        // but never hits this line
        this.logger.LogInformation("shutting down worker");
    }
like image 118
Daniel Lorenz Avatar answered Oct 20 '25 01:10

Daniel Lorenz



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!