码头重播请求超时
jetty replay request on timeout
我们在 Jetty 中遇到一个问题,如果我们没有完成来自异步上下文的请求,它会在超时时再次重播原始请求。这是行为,对于每个请求,我们都设置了一个带有超时的异步侦听器,因此我们有 2 个线程在运行,一个 (Jetty Thread1
) 正在侦听超时,另一个 (Thread2
) 正在服务线程。现在让我们说向客户端写入数据的时间比超时时间长,因为请求未完成超时线程被触发,它检查是否有人正在写入数据所以它 returns 静默。 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
}
这是正常现象。您已将请求置于异步状态,然后未处理超时,因此使用 ASYNC 的 DispatcherType 重新发送请求。
如果您添加自己的超时侦听器,并且在该超时时间内完成或分派 asyncContext,则 Jetty 不会重新分派它(除非您的侦听器调用分派)。
您还可以通过测试 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
{
}
});
我们在 Jetty 中遇到一个问题,如果我们没有完成来自异步上下文的请求,它会在超时时再次重播原始请求。这是行为,对于每个请求,我们都设置了一个带有超时的异步侦听器,因此我们有 2 个线程在运行,一个 (Jetty Thread1
) 正在侦听超时,另一个 (Thread2
) 正在服务线程。现在让我们说向客户端写入数据的时间比超时时间长,因为请求未完成超时线程被触发,它检查是否有人正在写入数据所以它 returns 静默。 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
}
这是正常现象。您已将请求置于异步状态,然后未处理超时,因此使用 ASYNC 的 DispatcherType 重新发送请求。
如果您添加自己的超时侦听器,并且在该超时时间内完成或分派 asyncContext,则 Jetty 不会重新分派它(除非您的侦听器调用分派)。
您还可以通过测试 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
{
}
});