10

長時間実行される HTTP 要求を処理する Jetty サーバーがあります。応答は別のプロセス X によって生成され、Jetty 要求が定期的にチェックするコレクター ハッシュになります。

3 つのケースがあります。

  1. プロセス X は、HTTP 要求のタイムアウト時間前に終了します - 問題ありません
  2. プロセス X は、リクエストのタイムアウト時間後に終了します - 問題ありません
  3. プロセス X が終了しない - 以下の例外が発生する

この状況 (3) を検出し、他の 2 つのケースを適切に機能させながら例外を防ぐにはどうすればよいですか?

例外:

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 リクエストの Jetty 継続:

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

}
4

2 に答える 2

2

ここでの問題は、AsyncContext#complete() の呼び出しではなく、コードの全体的な設計です。

Continuations (Servlet async の場合も同じ) は、非同期になるように設計されています。内部継続タイムアウトを利用する while ループは、ここにあってはなりません。これを行うことで、非同期設計を同期設計に変換しています。正しいことは、Continuation#addContinuationListener() を使用してリスナーを登録し、onTimeout() メソッドを実装して、タイムアウトのケースを適切に処理することです。

タイムアウト ロジックが終了したら、プロセス X ロジックをクラス AsyncHTTPRequestProcessor に移動し、コレクターを使用する必要がなくなることをお勧めします。処理中は、現在のスレッドがタイムアウトになることはないと想定する必要があります。これを行うことで、complete() の呼び出しが意味を成し、コレクターでの同時実行の問題の影響を受けなくなります。

于 2014-01-27T09:38:03.743 に答える