如何处理 Jetty 异常 - 长时间运行的 HTTP 请求超时,但它调用的进程永远不会终止,Jetty 不满意



我有一个处理长时间运行的HTTP请求的Jetty服务器 - 响应由不同的进程X生成,并最终进入Jetty请求定期检查的收集器哈希。

有3种情况:

  1. 进程 X 在 HTTP 请求的超时期限之前完成 -没关系
  2. 进程 X 在请求的超时期限后完成 - 否问题
  3. 进程 X 永不完成 - 出现以下异常

如何检测这种情况 (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)


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
        }
    }
}

这里的问题不在于你对AsyncContext#complete()的调用,而在于代码的整体设计。

延续(与 Servlet 异步相同)被设计为异步。使用内部延续超时的 while 循环不得在此处。通过执行此操作,您将异步设计转换为同步设计。正确的做法是使用 Continuation#addContinuationListener() 注册一个侦听器,并实现 onTimeout() 方法来适当地处理超时情况。

一旦你的超时逻辑出来了,我建议将进程X逻辑移动到AsyncHTTPRequestProcessor类,并不需要使用收集器。在处理过程中,您应该假设当前线程永远不会超时。通过这样做,您对 complete() 的调用是有意义的,您将不受收集器并发问题的影响。

在这种情况下,使用 try catch 块可能会有所帮助。

   try{
      ctx.complete()
   } catch (IllegalStateException e){
      //Handle it the way you prefer.
   }

最新更新