Java – how to cancel asyncresttemplate HTTP requests if they spend too much time?

Since the beginning, I have always confused how to handle interruptedexception and how to cancel HTTP requests correctly if they spend too much time I have a library that provides our customers with two methods, synchronous and asynchronous They can invoke methods that they think are appropriate for their purpose

>Executesync() – wait until I have the result and return the result. > Executeasync () – immediately returns a future that can be handled after other things are done, if necessary

They will pass a datakey object with a user ID and a timeout value We will find out which machine to call according to the user ID, and then use the machine to create a URL. We will use asyncresttemplate to make an HTTP call to the URL, and then send the response back to them according to whether it is successful or not

I am using the exchange method of asyncresttemplate, which returns a listenablefuture, and I want to use the asynchronous non blocking architecture of NiO based client connection to request non blocking IO, which is why I use asyncresttemplate Does this method correctly define my problem? The library will be used for production under very heavy load

Here is my interface:

public interface Client {
    // for synchronous
    public DataResponse executeSync(DataKey key);

    // for asynchronous
    public ListenableFuture<DataResponse> executeAsync(DataKey key);
}

The following is the interface I implemented:

public class DataClient implements Client {

    // using spring 4 AsyncRestTemplate
    private final AsyncRestTemplate restTemplate = new AsyncRestTemplate();

    // for synchronous
    @Override
    public DataResponse executeSync(DataKey keys) {
        Future<DataResponse> responseFuture = executeAsync(keys);
        DataResponse response = null;

        try {
            response = responseFuture.get(keys.getTimeout(),TimeUnit.MILLISECONDS);
        } catch (InterruptedException ex) {
            // do we need to catch InterruptedException here and interrupt the thread?
            Thread.currentThread().interrupt();
            // also do I need throw this RuntimeException at all?
            throw new RuntimeException("Interrupted",ex);
        } catch (TimeoutException ex) {
            DataLogging.logEvents(ex,DataErrorEnum.CLIENT_TIMEOUT,keys);
            response = new DataResponse(null,DataStatusEnum.ERROR);
            responseFuture.cancel(true); // terminating the tasks that got timed out so that they don't take up the resources?
        } catch (Exception ex) {
            DataLogging.logEvents(ex,DataErrorEnum.ERROR_CLIENT,DataStatusEnum.ERROR);
        }

        return response;
    }

    // for asynchronous     
    @Override
    public ListenableFuture<DataResponse> executeAsync(final DataKey keys) {

        final SettableFuture<DataResponse> responseFuture = SettableFuture.create();
        final org.springframework.util.concurrent.ListenableFuture orig = 
            restTemplate.exchange(createURL(keys),HttpMethod.GET,keys.getEntity(),String.class);

        orig.addCallback(
                new ListenableFutureCallback<ResponseEntity<String>>() {
                    @Override
                    public void onSuccess(ResponseEntity<String> result) {
                        responseFuture.set(new DataResponse(result.getBody(),DataErrorEnum.OK,DataStatusEnum.SUCCESS));
                    }

                    @Override
                    public void onFailure(Throwable ex) {
                        DataLogging.logErrors(ex,DataErrorEnum.ERROR_SERVER,keys);
                        responseFuture.set(new DataResponse(null,DataStatusEnum.ERROR));
                    }
                });

        // propagate cancellation back to the original request
        responseFuture.addListener(new Runnable() {
          @Override public void run() {
             if (responseFuture.isCancelled()) {
               orig.cancel(false); // I am keeping this false for Now
             }
          }
        },MoreExecutors.directExecutor());
        return responseFuture;
    }
}

Customers will call this from their code –

// if they are calling executeSync() method
DataResponse response = DataClientFactory.getInstance().executeSync(dataKey);

// and if they want to call executeAsync() method
Future<DataResponse> response = DataClientFactory.getInstance().executeAsync(dataKey);

The question now is –

>If the HTTP request is too long, can we interrupt the asyncresttemplate call? I actually called for canceling my future in the above code in the executesync method, but I don't know how to verify it to make sure what it's doing? I want to propagate the cancellation to the original future so that I can cancel the corresponding HTTP request (I may want to save resources), which is why I added a listener to my executeasync method I believe that we cannot interrupt the resttemplate call, but we are not sure whether asyncresttemplate can do this If we can interrupt the asyncresttemplate call, am I doing everything right to interrupt the HTTP call? Or is there a better / cleaner way to do this? Or do I even need to worry about canceling HTTP requests with asyncresttemplate with the current design?

// propagate cancellation back to the original request
    responseFuture.addListener(new Runnable() {
      @Override public void run() {
         if (responseFuture.isCancelled()) {
           orig.cancel(false); // I am keeping this false for Now
         }
      }
    },MoreExecutors.directExecutor());

Using the current setting, I can see that it is some time (not every time) when cancellationexception is thrown - does this mean that my HTTP request has been cancelled? > And I do the right thing in the catch block of interruptedexception in the executesync method? If not, what is the correct way to deal with this problem In my case, do I need to handle interruptedexception? > Is it true that asyncresttamplet uses blocking calls and requests per thread by default? If so, is there any way to have NiO based client connections in my current settings?

Any interpretation / code suggestions will be very helpful

Solution

First, why use settablefuture? Why can't I return the listenablefuture returned by asyncresttemplate?

1. Can we interrupt AsyncRestTemplate call if http request is taking too long?

Of course you do! You just need to call future Cancel method This method will interrupt the execution of the internal resttemplate actually used by asyncresttemplate

2. Also am I doing the right thing in catch block of InterruptedException in executeSync method?

As Phil and Danilo said, you do not need to interrupt the current thread in the interruptedexception catch block Anything you need to do as long as the execution request must be cancelled

In fact, I suggest you create a method to handle this behavior, like handleinterrupt, and use this method for timeoutexception and interruptedexception

3. Is it true that by default AsyncRestTamplete uses blocking calls and request per thread?

Yes The default constructor for asyncresttamplet internally uses simpleclienthttprequestfactory and simpleasynctaskexecutor

The taskexecutor always starts a threat for each task and never reuses threads, so it is inefficient:

* TaskExecutor implementation that fires up a new Thread for each task,* executing it asynchronously.
 *
 * Supports limiting concurrent threads through the "concurrencyLimit"
 * bean property. By default,the number of concurrent threads is unlimited.
 *
 * NOTE: This implementation does not reuse threads! Consider a
 * thread-pooling TaskExecutor implementation instead,in particular for
 * executing a large number of short-lived tasks.
 *

I suggest you use another configuration of asyncresttemplate

You should use the constructor of asyncresttemplate using another taskexecutor:

public AsyncRestTemplate(AsyncListenableTaskExecutor taskExecutor)

For example:

AsyncRestTemplate template = new AsyncRestTemplate(new ConcurrentTaskExecutor(Executors.newCachedThreadPool()));

This executorservice (executors. Newcachedthreadpool()) creates new threads as needed, but will reuse previously constructed threads when available

Or even better, you can use another requestfactory For example, you can use httpcomponentsasyncclienthttprequestfactory, use NiO internally, and just call the correct constructor of asyncresttemplate:

new AsyncRestTemplate(new HttpComponentsAsyncClientHttpRequestFactory())

Don't forget that the internal behavior of asyncresttemplate will depend on how you create the object

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>