2012-08-27 30 views
1

我有一个TimeoutException问题,我正在使用C#4.0(无法立即升级到4.5)和WCF。请注意,我不控制服务器,也看不到所使用的代码和或技术。这个问题发生在不同人制作的不同服务器上。许多并发异步调用客户端中的Random TimeoutException

我尽可能多地向许多服务器发送请求(比如10),每个服务器随时都有一个请求。他们每秒从2到30个请求。 30秒至5分钟之间,我会得到一些TimeoutException异常:

exception {"The HTTP request to 'http://xx.xx.xx.xx/service/test_service' has exceeded the allotted timeout of 00:02:10. The time allotted to this operation may have been a portion of a longer timeout."} System.Exception {System.TimeoutException}. 

Stack Trace : 
Server stack trace: 
    at System.Runtime.AsyncResult.End[TAsyncResult](IAsyncResult result) 
    at System.ServiceModel.Channels.ServiceChannel.SendAsyncResult.End(SendAsyncResult  result) 
    at System.ServiceModel.Channels.ServiceChannel.EndCall(String action, Object[] outs, IAsyncResult result) 
    at System.ServiceModel.Channels.ServiceChannelProxy.InvokeEndService(IMethodCallMessage methodCall, ProxyOperationRuntime operation) 
    at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message) 

Exception rethrown at [0]: 
    at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg) 
    at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type) 
    at Device.EndTest(IAsyncResult result) 
    at DeviceClient.EndTest(IAsyncResult result) in ... 
    at TestAsync(IAsyncResult ar) in ... 

的的InnerException是:

[System.Net.WebException] {"The request was aborted: The request was canceled."} System.Net.WebException 
at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult) 
at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelAsyncRequest.CompleteGetResponse(IAsyncResult result) 

Wireshark的告诉我,我甚至不打开一个连接(没有SYN)。所以这应该是一个客户端问题。我在TCPView中有许多TIME_WAIT连接

使用同步呼叫正在工作,但不可能。

请注意,在以下代码示例中,每个服务器都有一个方法调用。 (在我的情况,10个并发TestAsync)

(在实际项目中,我们使用CCR来代替信号灯,结果相同)

private void AsyncTest() 
{ 
    //GetServiceObject Will add custom bindings and more.. 
    Client client = ClientBuilder.GetServiceObject(); 

    while (true) 
    { 
     Semaphore semaphore = new Semaphore(0,1); 
     client.BeginTest(BeginTestCallback, new AsyncState 
     { 
      Client = client, 
      Semaphore = semaphore 
     }); 

     semaphore.WaitOne(); 
    } 
} 

private void BeginTestCallback(IAsyncResult asyncResult) 
{ 
    try 
    { 
     AsyncState state = asyncResult.AsyncState as AsyncState; 

     Client client = state.Client; 
     Semaphore semaphore = state.Semaphore; 

     Client.EndTest(asyncResult);  

     semaphore.Release(); 
    } 
    catch (Exception e) 
    { 
     //Will catch the exception here because of Client.EndTest(asyncResult) 
     Debug.Assert(false, e.Message); 
    } 
} 

我试着用

ServicePointManager.DefaultConnectionLimit = 200; 
ServicePointManager.MaxServicePointIdleTime = 2000; 

由于一些后建议, 没有成功。

即使我设置了高开放,发送,接收和关闭超时,它也会做同样的例外。 WCF似乎在发送请求时“卡住”了。服务器继续正确响应其他请求。

有什么想法吗?另外,如果我这样做(在回调中的BeginTest而不是while(true)),它将永远不会发生异常?!?!

private void AsyncTest() 
{ 
    //GetServiceObject Will add custom bindings and more.. 
    Client client = ClientBuilder.GetServiceObject(); 
    try 
    { 
     client.BeginTest(BeginTestCallback, new AsyncState 
     { 
      Client = client    
     }); 
    } 
    catch (Exception e) 
    { 
     Debug.Assert(false, e.Message); 
    } 
} 

private void BeginTestCallback(IAsyncResult asyncResult) 
{ 
    try 
    { 
     AsyncState state = asyncResult.AsyncState as AsyncState;   

     state.Client.EndTest(asyncResult); 

     state.Client.BeginTest(BeginTestCallback, state); 
    } 
    catch (Exception e) 
    { 
     //No Exception here 
     Debug.Assert(false, e.Message); 
    } 
} 
+0

注意,谢谢:)这可能是WCF中的错误?它发生在我们所有的机器上,并且尝试了很多来自其他来源的“修复”而没有成功。我可以在1分钟内复制它。每次调用同一个通道的ChannelFactory结果也是相同的。 – Dist01

回答

1

经过更多测试后,我发现如果begin/end机制没有在同一个线程池上执行,它会随机执行这种行为。

在第一种情况下,“AsyncTest”在具有ThreadStart和Thread的新线程中产生。在第二种情况下,只有第一个“开始”在专用线程上被调用,并且由于问题是随机发生的,所以在第一次请求时发生异常的可能性很小。另一个“开始”是在.net ThreadPool上进行的。

通过在第一种情况下使用Task.Factory.StartNew(()=> AsyncTest()),问题消失了。

在我的真实项目中,我仍然使用CCR(和CCR线程池)来完成所有任务,直到我必须调用开始/结束。我将使用.net线程池,现在一切正在运行。

任何人都可以更好地解释为什么WCF不喜欢在另一个线程池上调用?