简体   繁体   中英

How should a service exit to prevent an error?

I'm developing a Windows service in C#, .NET 6.0 following the instructions on https://learn.microsoft.com/en-us/do.net/core/extensions/windows-service The service runs as expected, but when I stop the service, it logs an error

A task was canceled.

Exception: System.Threading.Tasks.TaskCanceledException: A task was canceled. at AWLService.WindowsBackgroundService.ExecuteAsync(CancellationToken stoppingToken) in C:\Minerva\Projects\AWLService_Test\WindowsBackgroundService.cs:line 22

The ExecuteAsync for this program is as follows:

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        try
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                string joke = _jokeService.GetJoke();
                _logger.LogWarning("{Joke}", joke);

                await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken);
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "{Message}", ex.Message);

            // Terminates this process and returns an exit code to the operating system.
            // This is required to avoid the 'BackgroundServiceExceptionBehavior', which
            // performs one of two scenarios:
            // 1. When set to "Ignore": will do nothing at all, errors cause zombie services.
            // 2. When set to "StopHost": will cleanly stop the host, and log errors.
            //
            // In order for the Windows Service Management system to leverage configured
            // recovery options, we need to terminate the process with a non-zero exit code.
            Environment.Exit(1);
        }
    }

I've tried catching TaskCanceledException. When I do that and add Environment.Exit(0), I still get the error. If I take out Environment.Exit, the service terminates without an error, but it logs "Service stopped successfully" twice.

What is the proper way I should be ending my service?

Thank you.

EDIT: I added a handler for TaskCanceledException as follows:

catch (TaskCanceledException ex)
{
    //Do nothing, we're exiting normally.
    Environment.Exit(0);
}

When I do that, stopping the service through MMC shows an error "Error 1067: The process terminated unexpectedly" and a message is not logged indicating the service was stopped. Stopping it with sc on the command line doesn't show an error, but it also doesn't log a message that the service was stopped.

If I remove the Environment.Exit(0) line, MMC no longer shows an error, but the "Service stopped successfully" log message is written twice.

Catch the OperationCancelledException and log something different to the console in the handler. I suspect in your original handler (not shown) you were still probably doing this: _logger.LogError(ex, "{Message}", ex.Message);

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
    try
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            string joke = _jokeService.GetJoke();
            _logger.LogWarning("{Joke}", joke);

            await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken);
        }
    }
    catch (OperationCancelledException)
    {
        _logger.LogInformation("The service has stopped");
        Environment.Exit(0);
    }
    catch (Exception ex)
    {
        _logger.LogError(ex, "{Message}", ex.Message);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM