sefor
sefor

Reputation: 21

How to let windows to restart a .net service on failure

I am writing a windows service. Unfortunately, I am forced to use a library with a bug. When this bug appears I cannot get rid of it by other means than restarting the process. It is not enough to wrap all code in main function in a loop. I think that I need to either somehow unload and reload the external native library or let the Windows restart the service automatically on failure.

I tried configuring the service as follows:

sc failure "MyService" reset= 30 actions= restart/5000

This sometimes works. I can see that Windows is able to restart the service over and over. Unfortunately it depends on how the service crashes in c# code and in some cases does not restart the service. This is the code in c# I am using:

WebApplicationBuilder builder = WebApplication.CreateBuilder(options);

builder.Services.AddHostedService(provider => new MyHostedService());

builder.Host.UseWindowsService();
WebApplication app = builder.Build();
app.Run();

My observation is the following: If an uncaught exception is thrown in MyHostedService before first await, then app.Run() also throws an exception and Windows correctly restart the service as I want.

However, if MyHostedService works for a moment and awaits something several times then an exception occurs then app.Run() just returns and Windows do not restart the service.

This is logged to EventViewer:

The HostOptions.BackgroundServiceExceptionBehavior is configured to StopHost. A BackgroundService has thrown an unhandled exception, and the IHost instance is stopping. To avoid this behavior, configure this to Ignore; however the BackgroundService will not be restarted.

I tried throwing or returning non-zero from Main right after app.Run() but it does not have any effect.

I also considered changing the value of HostOptions.BackgroundServiceExceptionBehavior. But the other possibility is to Ignore the error which I don't want.

The strange behavior of the external library just needs restarting the process which does not work for me. Thank you very much in advance how to modify the code the way that windows restart the service on failure.

Upvotes: 1

Views: 765

Answers (2)

HackSlash
HackSlash

Reputation: 5813

Two things:

  1. To immediately allow the host to continue while your ExecuteAsync is getting warmed up you can place a await Task.Yield before anything that needs to be protected with a try and then use the try to avoid throwing exceptions at the host. Capture all errors in the background service and use them to set Environment.ExitCode, this is how you can flag that a critical service has failed to the host.

  2. There is another option in the service configuration that became available after Vista(2008). See here: Failing a Windows Service with an exit code

You can programatically set your service to restart on exit code from the command line:

sc.exe failureflag "ServiceName" 1

Main

WebApplicationBuilder builder = WebApplication.CreateBuilder(options);

builder.Services.AddHostedService(provider => new MyHostedService());

builder.Host.UseWindowsService();
WebApplication app = builder.Build();
await app.RunAsync();

MyHostedService

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
    try
    {
        // Tell the host to continue without us.
        await Task.Yield();

        // Your code goes here

    catch (Exception ex)
    {
        // Use to indicate failure to Windows Service Control Manager (SCM)
        Environment.ExitCode = ex.HResult;
    }
}

Upvotes: 0

sefor
sefor

Reputation: 21

I found the answer here.

To correctly allow the service to be restarted, you can call Environment.Exit with a non-zero exit code.

However the answer is still not very much satisfying. Even though an error has occured I would prefer to shutdown as much services and call as much Dispose methotds as I could. I would prefer the IHost.Run() to stop cleanly and return non-zero from main. This seems not to be possible. Environment.Exit(1) needs to be called from a hosted service which unfortunately must not be exited cleanly.

Upvotes: 1

Related Questions