0 Comments

TopShelf allows you to easily run a Console Application as a Windows Service. 

When configuring TopShelf, there is an `EnableServiceRecovery` method to specify what happens when things go wrong.

Which settings to use are a lot easier to work out once you realise that TopShelf just uses these during installation to set the Recovery options available for any Windows Service.

So if we have a simple application (based on the TopShelf quickstart docs) with recovery options set:

using System;
using System.Timers;
using Topshelf;

namespace TopShelfDemoService
{
    public class TownCrier
    {
        readonly Timer _timer;
        public TownCrier()
        {
            _timer = new Timer(1000) { AutoReset = true };
            _timer.Elapsed += (sender, eventArgs) => Console.WriteLine("It is {0} and all is well", DateTime.Now);
        }
        public void Start() { _timer.Start(); }
        public void Stop() { _timer.Stop(); }
    }

    public class Program
    {
        public static void Main()
        {
            HostFactory.Run(x =>
            {
                x.Service<TownCrier>(s =>
                {
                    s.ConstructUsing(name => new TownCrier());
                    s.WhenStarted(tc => tc.Start());
                    s.WhenStopped(tc => tc.Stop());
                });
                x.RunAsLocalSystem();

                x.SetDescription("Sample Topshelf Host");
                x.SetDisplayName("Stuff");
                x.SetServiceName("Stuff");

                x.EnableServiceRecovery(src =>
                {
                    src.OnCrashOnly();
                    src.RestartService(delayInMinutes: 0);
                    src.RestartService(delayInMinutes: 1);
                    src.SetResetPeriod(days: 1);
                });
            });
        }
    }
}

And we then install this as a service from a Command Prompt (as administrator):

TopShelfDemoService.exe install

From the Services management page we will then see the correspondence between the TopShelf `EnableServiceRecovery` configuration and the Services Recovery Properties:

image

 

The comments in the code below show how the two are related:

x.EnableServiceRecovery(src =>
{
  // Has no corresponding setting in the Recovery dialogue.
  // OnCrashOnly means the service will not restart if the application returns
  // a non-zero exit code.  By convention, an exit code of zero means ‘success’.
  src.OnCrashOnly();
  // Corresponds to ‘First failure: Restart the Service’
  // Note: 0 minutes delay means restart immediately
  src.RestartService(delayInMinutes: 0);
  // Corresponds to ‘Second failure: Restart the Service’
  // Note: TopShelf will configure a 1 minute delay before this restart, but the
  // Recovery dialogue only shows the first restart delay (0 minutes)
  src.RestartService(delayInMinutes: 1);
  // Corresponds to ‘Reset fail count after: 1 days’
  src.SetResetPeriod(days: 1);
});

In other words, when the service crashes, it will try and restart immediately.  If it crashes again, it will wait one minute then restart.  If it crashes again, it will do nothing.

If we want the service to keep restarting, no matter how many times it crashes, we just have to set the `Subsequent failures` setting:

x.EnableServiceRecovery(src =>
{
  src.OnCrashOnly();
  src.RestartService(delayInMinutes: 0);
  src.RestartService(delayInMinutes: 1);
  // Corresponds to ‘Subsequent failures: Restart the Service’
  src.RestartService(delayInMinutes: 5);
  src.SetResetPeriod(days: 1);
});
Post comment