Domanda

In AsyncHttpClient JDKFuture.get()

 public V  [More ...] get(long timeout, TimeUnit unit)  {
        V content = null;
        try {
            if (innerFuture != null) {
                content = innerFuture.get(timeout, unit);
            }
        } catch (TimeoutException t) {
            if (!contentProcessed.get() && timeout != -1 && 
              ((System.currentTimeMillis() -   touch.get()) <= responseTimeoutInMs)) {
                return get(timeout, unit);
            }

Why do we have 2 timeouts?

  1. timeout as param
  2. responseTimeoutInMs

Second timeout is hurting us, as the call doesn't comeout even after timeout expires. It keeps calling get() again recursively.

Will the connection get closed once responseTimeoutInMs is hit? We are trying to set it to lower than timeout.

È stato utile?

Soluzione

I assume you are referring to the method I found in the net:

public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
    V content = null;
    try {
        if (innerFuture != null) {
            content = innerFuture.get(timeout, unit);
        }
    } catch (TimeoutException t) {
        if (!contentProcessed.get() && timeout != -1 && ((System.currentTimeMillis() - touch.get()) <= responseTimeoutInMs)) {
            return get(timeout, unit);
        }

        if (exception.get() == null) {
            timedOut.set(true);
            throw new ExecutionException(new TimeoutException(String.format("No response received after %s", responseTimeoutInMs)));
        }
    } catch (CancellationException ce) {
    }

    if (exception.get() != null) {
        throw new ExecutionException(exception.get());
    }
    return content;
}

You can consider this class as being erroneous in several regards. The first mistake which jumps directly into the eye is the use of System.currentTimeMillis() instead of System.nanoTime(). System.currentTimeMillis() refers to the computers system clock which may be adjusted during the programs execution and hence can jump back and forth. Code dealing with timeouts should use System.nanoTime() which gives a value relative to the programs execution independent to the real world clock.

responseTimeoutInMs seems to be meant as a connection timeout but using it even when the timeout passed as parameter value has been expired is a violation of the Future contract. The correct behavior would be letting the get method time out even when the task represented by the Future may be still running.

But invoking the get method recursively is a double fault. Not only is the recursion dangerous as small timeout values may lead to a StackOverflowError; passing the same timeout again to itself means deferring the time out infinitely as every re-invocation will treat that value as relative to the current time.

Interestingly, even if the method gets to the point of timing out it will wrap the TimeoutException inside an ExecutionException reporting a completely wrong semantic to the caller.

I don’t believe that you will find someone on stackoverflow who can explain the rationale behind this implementation, if there is one at all. You will have to ask the supporter/authors of that code directly.

Altri suggerimenti

Don't use the JDK provider, it's broken and is being dropped in AHC 2. Use the Netty one, and upgrade to a modern version.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top