只有第一个调用成功了。所以,任何时候如果浏览器的两个连接都处在拥堵状态的话,那么你期待的其他调用也都将会超时。
在Pageflakes的运营中,我们曾经几乎每天都从客户端得到400个到600个超时错误报告,却从未能发现这是怎么发生的。起初怀疑是互联网连接过慢造成的,但是不可能如此多的用户都发生这种情况。后来,我们猜测是主机提供商的网络出现了问题。经过了大量的网络析去寻找问题是否是出现在网络上,但是依旧没有没有发现任何异常。接着使用SQL Profiler去查找是否是长时间运行的查询导致了ASP.NET请求执行时的超时。但是不幸,我们最终发现的是,大部分超时错误出现的情况都是先有一些坏的调用,然后好的调用也超时了。所以我们修改了Atlas运行时,引进了自动重试的功能,问题终于完全消失了。然而,自动重试需要对ASP.NET AJAX框架的Javascript做一次“心脏外科手术”,这个方法会要求每个调用在超时后都重试一次。为了实现它,我们需要截获所有web method调用并且在onFailure回调函数中作个钩子,如果失败的原因是超时,onFailure将再次调用相同的web method
另一个需要关注的发现是当我们外出旅行感到疲惫时,想通过酒店或机场的无线网络连接到互联网访问Pageflakes的时候,首次访问总是不成功,并且所有的web service调用在第一次尝试中总是失败。直到我们刷新之前都不会工作。这也是我们要实现web service调用立即自动重试的另一个主要原因,它正好可以解决这个问题。
这里我会告诉你怎么做。Sys$Net$WebServiceProxy$invoke函数是负责处理所有web service调用的。所以需要通过一个自定义onFailure回调函数来替换这个函数。只要有错误或者超时就会激发这个自定义回调函数。当有超时发生的时候,就会再次调用这个函数,重试就会发生。
Collapse
![]()
Sys.Net.WebServiceProxy.retryOnFailure =
![]()
function(result, userContext, methodName, retryParams, onFailure)
![]()
...{
![]()
if( result.get_timedOut() )
![]()
...{
![]()
if( typeof retryParams != "undefined" )
![]()
...{
![]()
debug.trace("Retry: " + methodName);
![]()
Sys.Net.WebServiceProxy.original_invoke.apply(this, retryParams );
![]()
}
![]()
else
![]()
...{
![]()
if( onFailure ) onFailure(result, userContext, methodName);
![]()
}
![]()
}
![]()
else
![]()
...{
![]()
if( onFailure ) onFailure(result, userContext, methodName);
![]()
}
![]()
}
![]()
![]()
![]()
Sys.Net.WebServiceProxy.original_invoke = Sys.Net.WebServiceProxy.invoke;
![]()
Sys.Net.WebServiceProxy.invoke =
![]()
function Sys$Net$WebServiceProxy$invoke(servicePath, methodName, useGet,
![]()
params, onSuccess, onFailure, userContext, timeout)
![]()
...{
![]()
var retryParams = [ servicePath, methodName, useGet, params,
![]()
onSuccess, onFailure, userContext, timeout ];
![]()
![]()
![]()
// 初始调用失败
![]()
// 处理自动重试
![]()
var newOnFailure = Function.createDelegate( this,
![]()
function(result, userContext, methodName)
![]()
...{
![]()
Sys.Net.WebServiceProxy.retryOnFailure(result, userContext,
![]()
methodName, retryParams, onFailure);
![]()
} );
![]()
![]()
![]()
Sys.Net.WebServiceProxy.original_invoke(servicePath, methodName, useGet,
![]()
params, onSuccess, newOnFailure, userContext, timeout);
![]()
}
![]()
运行的时候,它将把每个超时调用都重试一次

这里可以看到第一个方法成功了,所有其他超时的调用都会被重试。而且重试一次后的调用都成功了。发生这种情况是因为在重试中服务端的方法不会做超时处理。这证明了我们的实现方法是正确的。