mardi 31 mars 2015

How to properly cancel the HTTP request if they are taking too much time?

Since starting, I was always confuse of how to deal with InterruptedException and how to properly cancel the http request if they are taking too much time. I have a library in which I am making an URL basis on user id passed in DataKey object and then make http call to the URL using AsyncRestTemplate.


I am using exchange method of AsyncRestTemplate which returns back a ListenableFuture.


Below is my code -



public class DataClient implements Client {

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

@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) {
// log here and return DataResponse object
responseFuture.cancel(true); // terminating the tasks that got timed out so that they don't take up the resources? Will this work?
} catch (Exception ex) {
// log here and return DataResponse object
}

return response;
}

@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, DataErrorEnum.ERROR_SERVER,
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;
}
}


And we are calling like this -



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


Is it possible to interrupt AsyncRestTemplate call if request is taking too long? I believe, we cannot interrupt RestTemplate calls but not sure on AsyncRestTemplate whether we can do that or not.


Also I am not sure how do I verify whether AsyncRestTemplate calls can be interrupted or not.


Aucun commentaire:

Enregistrer un commentaire