Search code examples
c#windows-servicessingle-instancetopshelf

Force single instance of TopShelf service


I'm using TopShelf to host my windows service. This is my setup code:

static void Main(string[] args)
{
    var host = HostFactory.New(x =>
    {
        x.Service<MyService>(s =>
        {
            s.ConstructUsing(name => new MyService());
            s.WhenStarted(tc => tc.Start());
            s.WhenStopped(tc => tc.Stop());
        });

        x.RunAsLocalSystem();
        x.SetDescription(STR_ServiceDescription);
        x.SetDisplayName(STR_ServiceDisplayName);
        x.SetServiceName(STR_ServiceName);
    });

    host.Run();
}

I need to ensure that only one instance of my application can be running at the same time. Currently you can start it as windows service and any number of console apps simultaneously. If application detects other instance during startup it should exit.

I really like mutex based approach but have no idea how to make this working with TopShelf.


Solution

  • This is what worked for me. It turned out to be really simple - mutex code exists only in Main method of console app. Previously I had a false negative test with this approach because I had no 'Global' prefix in mutex name.

    private static Mutex mutex = new Mutex(true, @"Global\{my-guid-here}");
    
    static void Main(string[] args)
    {
        if (mutex.WaitOne(TimeSpan.Zero, true))
        {
            try
            {
                var host = HostFactory.New(x =>
                {
                    x.Service<MyService>(s =>
                    {
                        s.ConstructUsing(name => new MyService());
                        s.WhenStarted(tc =>
                        {
                            tc.Start();
                        });
                        s.WhenStopped(tc => tc.Stop());
                    });
                    x.RunAsLocalSystem();
                    x.SetDescription(STR_ServiceDescription);
                    x.SetDisplayName(STR_ServiceDisplayName);
                    x.SetServiceName(STR_ServiceName);
                });
    
                host.Run();
            }
            finally
            {
                mutex.ReleaseMutex();
            }
        }
        else
        {
            // logger.Fatal("Already running MyService application detected! - Application must quit");
        }
    }