aweyeahdawg
aweyeahdawg

Reputation: 1016

Configure Windows Service to restart on both graceful AND ungraceful shutdown

I am aware of the Recovery section of the Service control, and how we can set an app to restart after failure.

I have created a .NET 6 worker service to run as a windows service. The problem is that whenever there is an exception in the code, the app logs the error but then shuts down gracefully. This does not signal to windows that the service should be restarted since it returns an exit code of 0.

I've tried returning an exit code of -1 (by setting Environment.ExitCode and returning -1 from Main()) but it's ignored.

I've also tried setting the exit code of the underlying WindowsServiceLifetime and that also does not work.

Are there any ways to have the SCM restart the service no matter how it shut down?

Upvotes: 1

Views: 574

Answers (1)

Sandy
Sandy

Reputation: 1504

Exceptions should not bring down the host. Exceptions do not bring down IIS and they should not bring down a Windows Service.

You should put try/catch where work begins – every endpoint and background service. In the catch you should log the error.

Here is an endpoint example:

[Route("Get")]
[HttpGet]
public async Task<IActionResult> GetAsync()
{
    try
    {
        return Ok(await BusinessRules.GetSomethingAsync());
    }
    catch (Exception e)
    {
        _logger.LogError(e, e.Message);
        throw;
    }
}

Here is a background service example:

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
    while (!stoppingToken.IsCancellationRequested)
    {
        try
        {
            //Need a try/catch round Task.Delay because exception will the thrown
            //if stoppingToken is activated and we don't care about logging this exception.
            try
            {
                await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken);
            }
            catch { }
        
            await BusinessRules.DoSomethingAsync(stoppingToken);
        }
        catch (Exception e)
        {
            _logger.LogError(e, e.Message);

            //In a loop, log file can fill up quickly unless we slow it down after error.
            try
            {
                await Task.Delay(TimeSpan.FromSeconds(10), stoppingToken);
            }
            catch { }
        }
    }
}

Upvotes: 1

Related Questions