.NET 6 worker service error when stopping

Viewed 126

Can someone explain this message and the Environment.Exit(1) statement? I'm testing out creating a windows service in .NET 6 and this advice is shown in the Microsoft example.

https://docs.microsoft.com/en-us/dotnet/core/extensions/windows-service

If the Environment.Exit(1) statement is included, when stopping the service, it returns the error "Windows could not stop the TestService service on Local Computer. Error 1067:The process terminated unexpectedly."

If I comment out that line the service stops without the windows error.

        // 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);
2 Answers

The method Exit is called in a catch statement, because the original author of the code snippet was trying to show you that within a Windows service app what's the standard approach to notify the user/machine administrators that an error occurred.

If you don't know what are "recovery options", I suggest you dig deeper into articles like this.

In short, it is desired to see the error "Windows could not stop the TestService service on Local Computer. Error 1067:The process terminated unexpectedly", because we want to recover from such errors.

I can't imagine the correct default behavior for stopping a service through Services.msc results in an error. And in my case, the OS was automatically restarting the service after a few minutes because of the error.

My quick and dirty solution was to catch the TaskCanceledException that gets thrown when stopping the service and just let the service quit without erroring. It would be better to figure out how to not throw the TaskCanceledException during a planned stop.

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
    try
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            _logger.LogInformation("Entering 5 minute processing window.");

            // Perform logic

            await Task.Delay(5 * 60 * 1000, stoppingToken); // Run once every 5 mins
        }
    }
    catch (TaskCanceledException ex)
    {
        _logger.LogInformation("Service async task was cancelled. Service will stop execution.");
    }
    catch (Exception ex)
    {
        _logger.LogError(ex, "Error in Service: {Message}", ex.Message);
        Environment.Exit(1);
    }
}
Related