Topshelf 托管的 WCF 服务需要很长时间才能关闭

发布于 2024-09-26 06:00:15 字数 3559 浏览 7 评论 0原文

我正在使用 Topshelf 将 WCF 服务托管为 Windows 服务。即使只是在控制台上运行,在我向其发送 Ctrl-C 后也需要非常长的时间才能关闭,并且在作为服务运行时会反映这一点。在我的本地计算机上,调用 svcHost.Close(new TimeSpan(0)) 需要 1 毫秒,但在 Topshelf 调用的 Stop 方法结束和代码脱离 Runner.Host() 方法之后之间需要 10240 毫秒。这不太好,但在我尝试过的生产服务器上,第二个值是 70 秒。这远远超过 Windows 在判定该服务是垃圾之前提供服务的 30 秒时间。

这是我的 Topshelf 代码和服务代码。我已经对两者进行了很多剥离,以删除 Log4Net 日志记录和异常处理,因为我已经验证没有发生异常。

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);
    }
}

10 多秒和 70 多秒似乎太“默认”了,所以我到处寻找超时设置尽可能低的值,但似乎没有一个有任何好处。这是我的 app.config 代码。

<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>

那么我该怎么做才能让 WCF 更快地关闭呢?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

故事未完 2024-10-03 06:00:15

在 2.1.0.0 中尝试关闭时,Topshelf 似乎确实挂起。这是我们必须研究的事情。

此外,您始终可以从 http://teamcity.codebetter.com/ 下载最新的 Topshelf 开发分支二进制文件。以访客身份登录并找到 Masstransit 项目,构建位于该部分下。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文