views:

51

answers:

1

I'm using Topshelf to host a WCF Service as a Windows Service. Even when just running on the console, it takes an exceptionally long time to shut down after I send it a Ctrl-C, and this is mirrored when running as a service. On my local machine, it takes 1ms to call svcHost.Close(new TimeSpan(0)), but 10240ms between the end of my Stop method that Topshelf calls and after the code falls out of the Runner.Host() method. This isn't great, but on a production server I tried, the second value is 70s. That's WAY more than the 30 seconds Windows will give a service before it decides the service is a piece of junk.

Here's my Topshelf code and service code. I've stripped both down a lot to remove the Log4Net logging and exception handling, because I've verified exceptions aren't occurring.

public class Service
{
    private ServiceHost svcHost;

    public void Start()
    {
        string bindUri = "net.tcp://MyMachineName:10000";
        svcHost = new ServiceHost(typeof(MyServiceClass));
        svcHost.AddServiceEndpoint(typeof(IMyService), new NetTcpBinding("tcp"), bindUri);
        svcHost.Description.Behaviors.Add(new LoggerBehavior());
        svcHost.Open();
    }

    public void Stop()
    {
        svcHost.Close(new TimeSpan(0));
        svcHost = null;
    }
}

class Program
{
    static void Main(string[] args)
    {

        Stopwatch sw = new Stopwatch();
        var cfg = RunnerConfigurator.New(c =>
        {
            c.ConfigureService<Service>(s =>
            {
                s.Named("MyServiceName");
                s.HowToBuildService(x => new Service());
                s.WhenStarted(service => service.Start());
                s.WhenStopped(service =>
                    {
                        sw.Start();
                        service.Stop();
                        sw.Stop();
                        Console.WriteLine("Stop Time: {0}ms", sw.ElapsedMilliseconds); // usually 1-2ms
                        sw.Reset();
                        sw.Start();
                    });
            });
            c.RunAsLocalSystem();
            c.SetDescription("Runs MyServiceName.");
            c.SetDisplayName("MyServiceName");
            c.SetServiceName("MyServiceName");
        });

        Runner.Host(cfg, args);

        sw.Stop();
        // ~10 seconds on my machine, ~70s on a production server!
        Console.WriteLine("Finish Time: {0}ms", sw.ElapsedMilliseconds);
    }
}

Just over 10 seconds and just over 70 seconds seems far too "defaulty" so I've searched high and low for timeouts to set as low as possible but none of them seems to do any good. Here's my app.config code.

<system.serviceModel>
    <bindings>
        <netTcpBinding>
            <binding name="tcp"
                     maxReceivedMessageSize="52428800"
                     transferMode="Buffered"
                     openTimeout="0:00:01"
                     sendTimeout="0:00:01"
                     receiveTimeout="0:00:01" 
                     closeTimeout="0:00:01">
                <security mode="None" />
            </binding>
        </netTcpBinding>
    </bindings>
    <behaviors>
        <serviceBehaviors>
            <behavior name="MyServiceBehavior">
                <serviceMetadata />
                <serviceDebug includeExceptionDetailInFaults="true" />
                <serviceThrottling maxConcurrentCalls="100" maxConcurrentInstances="100" maxConcurrentSessions="100" />
                <serviceTimeouts transactionTimeout="0:00:01" />
            </behavior>
        </serviceBehaviors>
    </behaviors>
    <services>
        <service name="MyApp.MyServiceClass" behaviorConfiguration="MyServiceBehavior">
            <host>
                <timeouts openTimeout="0:00:01" closeTimeout="0:00:01" />
            </host>
        </service>
    </services>
</system.serviceModel>

So what can I do to get WCF to shut down faster?

A: 

It does appear that Topshelf is hanging when attempting to shutdown in 2.1.0.0. This is something we'll have to look into.

Additionally, you can always download the latest Topshelf develop branch binaries from http://teamcity.codebetter.com/ . Login as guest and find the Masstransit project, the build is under that section.

Travis
Is there a pending issue on Topshelf for this? I don't see it on the list of issues on GitHub. If someone is already working on the issue, great, but if not, I'd be willing to take a crack at it if you could point me in the right direction.
David