Search code examples
.net-coresystemd.net-7.0

Worker Service's ExecuteAsync doesn't stop gracefully


I'm developing a worker-service application using .net7, and I'm able to run it as a unit on systemd.

I wish to have the application execute some code to gracefully shutdown, whenever a 'systemctl stop my.service' is issued, however it seems like it immediately shuts down

Program.cs:

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

    public Worker(ILogger<Worker> logger, IConfiguration config)
    {
        _logger = logger;
        _config = config;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {


        while (!stoppingToken.IsCancellationRequested)
        {
            _logger.LogInformation("{env} - Worker running at: {time}",_config["env"], DateTimeOffset.Now);
            await Task.Delay(5000, stoppingToken);
        }

        _logger.LogInformation("this line is never executed after stop");
    }

    public override async Task StopAsync(CancellationToken stoppingToken)
    {

        await base.StopAsync(stoppingToken);

        _logger.LogInformation("this line is actually executed after stop");
    }
}

Both the output from inside the loop and the StopAsync are being printed successfully during run time and stop, I use the following to access it:

journalctl --unit=my.service -n 50 --no-pager


Solution

  • Both the output from inside the loop and the StopAsync are being printed successfully during run time and stop

    Right, so it is exiting gracefully. The base.StopAsync is cancelling the token passed to ExecuteAsync. This almost always causes Task.Delay to throw an OperationCanceledException, causing the ExecuteAsync to complete.

    If you want code in ExecuteAsync to always try to run during shutdown, put it in a finally block.