"Locker is not reentrant" 异步 java jetty servlet 长轮询
"Locker is not reentrant" in asynchronous java jetty servlet long polling
我遇到了以下情况:我正在尝试在 java 中实现一个长轮询 servlet(将 运行 放在码头上)。我正在使用 AsyncContext 和 TimerTask 来实现这一点。
我有一个会话 class 有这个方法:
public boolean setLongPollingContext(final AsyncContext ctx) {
if (ctx==null)
return false;
this.longPollContext = ctx;
this.alertHandler = new AlertNotificationHandler() {
@Override
public void onNewAlert() {
}
@Override
public void onTimeout() {
System.out.println("*** timeout ***");
HttpServletResponse response = (HttpServletResponse)ctx.getResponse();
response.setStatus(408); // timeout
try {
response.getWriter().write("Timeout");
} catch (IOException e) {
e.printStackTrace();
}
ctx.complete();
}
};
this.alertHandler.setTimeout(this.longPollingInterval); // 31 seconds
return true;
}
(setTimeout 只是启动一个计时器线程,它会在 31 秒内调用 "onTimeout")
我是这样称呼它的:
final AsyncContext asyncCtx = request.startAsync(request, response);
session.setLongPollingContext(asyncCtx);
它在 30 秒内运行良好(这显然是 jetty 9.3 中的默认 ssl/http 线程超时)。
超过 30 秒后,我遇到了与超时相关的问题,我通过在我的 appease/start.d/ssl.ini 文件中设置此行来修复该问题:
## Connector idle timeout in milliseconds
jetty.ssl.idleTimeout=330000
我不再遇到超时问题,但现在我遇到了更奇怪的事情:
Exception in thread "Timer-0"
java.lang.IllegalStateException: Locker is not reentrant
at org.eclipse.jetty.util.thread.Locker.concLock(Locker.java:85)
at org.eclipse.jetty.util.thread.Locker.lock(Locker.java:61)
at org.eclipse.jetty.server.HttpChannelState.getStatusString(HttpChannelState.java:166)
at org.eclipse.jetty.server.HttpChannelState.complete(HttpChannelState.java:481)
at org.eclipse.jetty.server.AsyncContextState.complete(AsyncContextState.java:92)
at com.theobroma.paranoidandroid.session.ProxyClientSession.onTimeout(ProxyClientSession.java:60)
at com.theobroma.paranoidandroid.session.AlertNotificationHandler.run(AlertNotificationHandler.java:25)
at java.util.TimerThread.mainLoop(Unknown Source)
at java.util.TimerThread.run(Unknown Source)
Google 没有给我任何相关的向量。
jetty 还需要配置什么吗?
有没有一种方法可以在不更改配置文件的情况下设置这些配置选项(通过代码,例如使用注释或设置一些静态变量?)
谢谢!
Joakim Erdfelt 给了我一些非常有用的提示,我将在答案中汇总这些提示,因为它为我解决了这个问题。
所以,问题似乎是 AsyncContext 有自己的超时,在我的设置中默认为 30 秒(我猜它与码头的 30 秒无关,这只是一种误导巧合)
一旦异步上下文超时,请求和响应流将关闭,无法再次打开,因此会出现错误。
解决方案是增加异步上下文的超时时间:
ctx.setTimeout(this.longPollingInterval+1000);
我为此添加了一些额外的时间,以确保它不会在我自己的超时线程之前超时。
有一种方法可以将超时事件的侦听器分配给异步上下文。我将查看并使用它代替我自己的超时线程。我对 Java 很陌生,所以我不知道这个:)
我遇到了以下情况:我正在尝试在 java 中实现一个长轮询 servlet(将 运行 放在码头上)。我正在使用 AsyncContext 和 TimerTask 来实现这一点。
我有一个会话 class 有这个方法:
public boolean setLongPollingContext(final AsyncContext ctx) {
if (ctx==null)
return false;
this.longPollContext = ctx;
this.alertHandler = new AlertNotificationHandler() {
@Override
public void onNewAlert() {
}
@Override
public void onTimeout() {
System.out.println("*** timeout ***");
HttpServletResponse response = (HttpServletResponse)ctx.getResponse();
response.setStatus(408); // timeout
try {
response.getWriter().write("Timeout");
} catch (IOException e) {
e.printStackTrace();
}
ctx.complete();
}
};
this.alertHandler.setTimeout(this.longPollingInterval); // 31 seconds
return true;
}
(setTimeout 只是启动一个计时器线程,它会在 31 秒内调用 "onTimeout")
我是这样称呼它的:
final AsyncContext asyncCtx = request.startAsync(request, response);
session.setLongPollingContext(asyncCtx);
它在 30 秒内运行良好(这显然是 jetty 9.3 中的默认 ssl/http 线程超时)。
超过 30 秒后,我遇到了与超时相关的问题,我通过在我的 appease/start.d/ssl.ini 文件中设置此行来修复该问题:
## Connector idle timeout in milliseconds
jetty.ssl.idleTimeout=330000
我不再遇到超时问题,但现在我遇到了更奇怪的事情:
Exception in thread "Timer-0"
java.lang.IllegalStateException: Locker is not reentrant
at org.eclipse.jetty.util.thread.Locker.concLock(Locker.java:85)
at org.eclipse.jetty.util.thread.Locker.lock(Locker.java:61)
at org.eclipse.jetty.server.HttpChannelState.getStatusString(HttpChannelState.java:166)
at org.eclipse.jetty.server.HttpChannelState.complete(HttpChannelState.java:481)
at org.eclipse.jetty.server.AsyncContextState.complete(AsyncContextState.java:92)
at com.theobroma.paranoidandroid.session.ProxyClientSession.onTimeout(ProxyClientSession.java:60)
at com.theobroma.paranoidandroid.session.AlertNotificationHandler.run(AlertNotificationHandler.java:25)
at java.util.TimerThread.mainLoop(Unknown Source)
at java.util.TimerThread.run(Unknown Source)
Google 没有给我任何相关的向量。
jetty 还需要配置什么吗?
有没有一种方法可以在不更改配置文件的情况下设置这些配置选项(通过代码,例如使用注释或设置一些静态变量?)
谢谢!
Joakim Erdfelt 给了我一些非常有用的提示,我将在答案中汇总这些提示,因为它为我解决了这个问题。
所以,问题似乎是 AsyncContext 有自己的超时,在我的设置中默认为 30 秒(我猜它与码头的 30 秒无关,这只是一种误导巧合)
一旦异步上下文超时,请求和响应流将关闭,无法再次打开,因此会出现错误。
解决方案是增加异步上下文的超时时间:
ctx.setTimeout(this.longPollingInterval+1000);
我为此添加了一些额外的时间,以确保它不会在我自己的超时线程之前超时。
有一种方法可以将超时事件的侦听器分配给异步上下文。我将查看并使用它代替我自己的超时线程。我对 Java 很陌生,所以我不知道这个:)