超时时跳码重播请求

时间:2015-06-11 16:56:24

标签: timeout jetty redo replay

我们在Jetty遇到一个问题,如果我们没有完成异步上下文的请求,那么在超时时它会再次重播原始请求。这是行为,对于每个请求我们设置一个带有超时的异步监听器,所以我们有两个正在运行的线程,一个(Jetty Thread1)正在监听超时而其他(Thread2)正在服务线程。现在让我们说写入客户端的数据需要比超时更长的时间,因为请求未完成超时线程被触发,它会检查有人正在写入数据以便它以静默方式返回。 Jetty不喜欢以静默方式返回,它会重新发送请求,以便创建另一个服务和超时线程,并继续执行,直到写入数据并完成异步上下文。

相关代码在此处 - HttpChannelState方法中的expired()

if (aListeners!=null)
{
   for (AsyncListener listener : aListeners)
   {
       try
       {
           listener.onTimeout(event);
       }
       catch(Exception e)
       {
           LOG.debug(e);
           event.setThrowable(e); 
           _channel.getRequest().setAttribute(RequestDispatcher.ERROR_EXCEPTION,e);
           break;
        }
    }
}


boolean dispatch=false;
synchronized (this)
{
    if (_async==Async.EXPIRING)
    {
        _async=Async.EXPIRED;
        if (_state==State.ASYNC_WAIT)
        {
            _state=State.ASYNC_WOKEN;
            dispatch=true;
        }
    }
}
if (dispatch)
scheduleDispatch();   // <------------ dispatch again why
}

1 个答案:

答案 0 :(得分:4)

这是正常行为。您已将请求置于异步状态,然后未处理超时,因此请求是使用DispatcherType为ASYNC的redispatch。

如果您添加自己的超时侦听器并在该超时内完成或调度asyncContext,则jetty不会重新发送它(除非您的侦听器调用dispatch)。

您还可以使用DispatcherType测试来保护您的异步servlet代码,但如果您有多个可能被处理为异步的问题,则可能会混淆。

    asyncContext.addListener(new AsyncListener()
    {

        @Override
        public void onTimeout(AsyncEvent event) throws IOException
        {
            event.getAsyncContext().complete();

        }

        @Override
        public void onStartAsync(AsyncEvent event) throws IOException
        {                
        }

        @Override
        public void onError(AsyncEvent event) throws IOException
        {
        }

        @Override
        public void onComplete(AsyncEvent event) throws IOException
        {
        }
    });