Search code examples
background-service.net-core-3.0

Manage cancellation on the Token in a .NET Core 3.0 Worker Service


I'm developing my first .NET Core 3.0 Worker Service to run it as a Windows Service.

Here there is the code I used for the test.

Debugging I see that stopping the windows service, the StopAsync() will be executed, but the ExecuteAsync() terminates due to the exception OperationCanceledException (thrown from the line Task.Delay(1000, stoppingToken)). Of course I can catch it but what I would like to do is complete the method flow in order to exit gracefully.

Is there any way to avoid the exception and just exit according to the while condition?

namespace Enerj.MyAppCore.WorkerService
{
    public class Worker : BackgroundService
    {
        private readonly ILogger<Worker> _logger;
        bool exit = false;

        public Worker(ILogger<Worker> logger)
        {
            _logger = logger;
            _logger.LogInformation("ctor");
        }

        public override async Task StartAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation("Start");
            await base.StartAsync(cancellationToken);
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
                await Task.Delay(1000, stoppingToken);
            }
            System.Diagnostics.Debugger.Break();
        }

        public override async Task StopAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation("Stopping");
            await Task.CompletedTask;
        }
    }
}

Solution

  • MY SOLUTION

    As evident from the code, the application spends almost all the time in the Task.Delay, so it is correct that Exception is thrown from that code.

    I changed the code as follows.

    while (!stoppingToken.IsCancellationRequested)
    {
        _logger.LogInformation($"Worker running at: {DateTime.Now}");
    
        try
        {
            await Task.Delay(1000, stoppingToken);
        }
        catch (Exception exc)
        {
            _logger.LogError($"Error running at: {DateTime.Now}");
        }
    
        System.Diagnostics.Debugger.Break();
    
        // Other code
    }