为什么WCF不支持服务端超时?

21

我们最近发现,WCF不支持在服务端(注意,是服务端,而不是客户端)超时操作。虽然客户端在指定时间后会断开连接,但我们的测试表明,在netNamedPipeBinding、netTcpBinding和basicHttpBinding中,我们指定的任何超时都不会导致服务操作停止一旦被调用。以下是我们尝试过的具体绑定配置:

<bindings>
  <netNamedPipeBinding>
    <binding name="TestServiceBindingConfigurationNamedPipe"
             receiveTimeout="00:00:05"
             sendTimeout="00:00:05"
             closeTimeout="00:00:05"
             openTimeout="00:00:05" />
  </netNamedPipeBinding>
  <netTcpBinding>
    <binding name="TestServiceBindingConfigurationTcp"
             receiveTimeout="00:00:05"
             sendTimeout="00:00:05"
             closeTimeout="00:00:05"
             openTimeout="00:00:05" />
  </netTcpBinding>
  <basicHttpBinding>
    <binding name="TestServiceBindingConfigurationBasicHttp"
             receiveTimeout="00:00:05"
             sendTimeout="00:00:05"
             closeTimeout="00:00:05"
             openTimeout="00:00:05" />
  </basicHttpBinding>
</bindings>

我们的测试服务实现如下:

public class TestServiceImpl : ITestService
{
    public TestResult TestIt(TestArgs args)
    {
        var stopwatch = new Stopwatch();
        stopwatch.Start();

        // this is a contrived example, but it shows that WCF never stops this thread
        while (true)
        {
            Console.WriteLine("{0}> I'm running forever...", stopwatch.Elapsed);
        }

        return new TestResult {Result = "Args were " + args.Args};
    }
}

使用netNamedPipeBinding和netTcpBinding,我们的客户端应用程序在5秒后会超时,但服务将继续无限期运行。

这引出了我的问题 - 这是一个错误吗?WCF是否有特定的原因不想超时运行时间长于预期的服务?

从我的角度来看,一些可能存在的负面影响包括:

  1. 服务实例的默认限制为10。因此,如果您的服务中有永远运行的错误代码,并且它被调用了10次,您的服务将完全关闭;不接受任何新连接。
  2. 除非进行自定义日志记录或可能使用性能计数器,否则没有任何可见性表明服务正在永久运行。
  3. 如果没有其他机制超时操作,则正在使用服务调用的任何资源可能会无限期保持(例如SQL行、页和表锁)。
3个回答

9
如果你有一些糟糕的代码会一直运行,那么设置超时可能只会让事情变得更糟。如果可能的话,请修复这些糟糕的代码!请参考Eric Lippert的文章Careful with that axe,了解这些情况。
如果这是在开发中,你可以尝试设置一个System.Threading.Timer,在你的服务实现中调用serviceCallThread.Abort()。但是,在返回之前一定要彻底停用计时器--这种方法非常容易出错,因为涉及到并发问题、不拥有服务调用所在的线程、ThreadAbortException的奇怪行为以及Eric所解释的关于盲目终止已经失控的代码的问题。

我们想要的是能够看到永远运行的糟糕代码。我们宁愿让它被中止并抛出TimeoutException,也不愿意让它潜在地占用CPU而没有任何可见性告诉我们需要修复的糟糕代码。 - David Mohundro
2
是的,我是说删除运行时间过长的代码是有道理的。但是当你不希望它永远运行时怎么办呢?当所有客户端都已经断开连接很久了,你如何知道服务仍在执行并且处于什么状态? - Jab
关于设置一个计时器来中止服务线程,这正是我们最终实现的。我提出这个问题的部分原因是因为我真的不太舒服自己编写这段代码,因为正如你所说,它非常容易出错。我一直希望我错过了某个配置行! - David Mohundro

2

我也遇到过这个问题……我想不出来为什么他们不会将服务端操作超时作为平台的一部分。


0

怎么样:

<system.web>
    <httpRuntime executionTimeout="inSeconds"/>
</system.web>

从.NET 3.0 SP1开始,这也不再起作用。 - gravidThoughts

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接