我有一个Jetty服务器处理长时间运行的HTTP请求 - 响应是由不同的进程X生成的,最后是Jetty请求定期检查的收集器哈希。
有3例:
如何检测这种情况(3)并防止异常,同时允许其他两种情况正常工作?
例外:
2012-06-18 00:13:31.055:WARN:oejut.QueuedThreadPool:
java.lang.IllegalStateException: IDLE,initial
at org.eclipse.jetty.server.AsyncContinuation.complete(AsyncContinuation.java:569)
at server.AsyncHTTPRequestProcessor.run(AsyncHTTPRequestProcessor.java:72)
at org.eclipse.jetty.server.handler.ContextHandler.handle(ContextHandler.java:1119)
at org.eclipse.jetty.server.AsyncContinuation$1.run(AsyncContinuation.java:875)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:599)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:534)
at java.lang.Thread.run(Thread.java:679)
Jetty继续HTTP请求:
public class AsyncHTTPRequestProcessor implements Runnable {
private ConcurrentHashMap<String, String> collector;
private Logger logger;
private AsyncContext ctx;
//Defined this here because of strange behaviour when running junit
//tests and the response json string being empty...
private String responseStr = null;
public AsyncHTTPRequestProcessor(AsyncContext _ctx,
ConcurrentHashMap<String, String> _collector, Logger _logger) {
ctx = _ctx;
collector = _collector;
logger = _logger;
}
@Override
public void run() {
logger.info("AsyncContinuation start");
//if(!((AsyncContinuation)ctx).isInitial()){
String rid = (String) ctx.getRequest().getAttribute("rid");
int elapsed = 0;
if(rid !=null)
{
logger.info("AsyncContinuation rid="+rid);
while(elapsed<ctx.getTimeout())
{
if(collector.containsKey(rid)){
responseStr = collector.get(rid);
collector.remove(rid);
logger.info("--->API http request in collector:"+responseStr);
ctx.getRequest().setAttribute("status",200);
ctx.getRequest().setAttribute("response", responseStr);
ctx.getRequest().setAttribute("endTime",System.currentTimeMillis());
//ctx.complete();
break;
}
try {
Thread.sleep(10);
elapsed+=10;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//}
logger.info("Collector in async stuff:");
for(String key:collector.keySet()){
logger.info(key+"->"+collector.get(key));
}
for(Entry<String, String> x:collector.entrySet()){
logger.info(x.getKey()+"->"+x.getValue());
}
ctx.complete(); <---- this line 72
}
}
}
答案 0 :(得分:2)
这里的问题不是你对AsyncContext#complete()的调用,而是代码的总体设计。
Continuations(Servlet异步同样的事情)被设计为异步。使用内部延续超时的while循环不能在这里。您正在通过执行此操作将异步设计转换为同步设计。正确的做法是使用Continuation#addContinuationListener()注册一个监听器,并实现onTimeout()方法来适当地处理超时情况。
一旦你的超时逻辑结束,我建议将进程X逻辑移到AsyncHTTPRequestProcessor类,并从需要使用收集器开始。在处理过程中,您应该假设当前线程永远不会超时。通过执行此操作,您对complete()的调用会产生敏感,您将免于收集器上的并发问题。
答案 1 :(得分:0)
在这种情况下,使用try catch块可能有所帮助。
try{
ctx.complete()
} catch (IllegalStateException e){
//Handle it the way you prefer.
}