Как я могу прервать вызов RestTemplate, как только мой поток будет прерван?
Мне нужно сделать библиотеку, в которой у меня будет синхронная и асинхронная функция.
executeSynchronous()
- ждет, пока у меня не появится результат, возвращает результат.executeAsynchronous()
- немедленно возвращает Future, который может быть обработан после выполнения других действий, если это необходимо.Основная логика моей библиотеки
Клиент будет использовать нашу библиотеку и позвонит ей, передавDataKey
застройщик объекта. Затем мы создадим URL, используя этоDataKey
выполнить объект и выполнить HTTP-вызов клиента на этот URL, выполнив его, и после того, как мы получим ответ обратно в виде строки JSON, мы отправим эту строку JSON нашему клиенту в том виде, как он есть, создавDataResponse
объект. Какой-то клиент позвонитexecuteSynchronous()
а некоторые могут позвонитьexecuteAsynchronous()
вот почему я должен предоставить два метода отдельно в моей библиотеке.
Интерфейс:
public interface Client {
// for synchronous
public DataResponse executeSynchronous(DataKey key);
// for asynchronous
public Future<DataResponse> executeAsynchronous(DataKey key);
}
И тогда у меня есть мойDataClient
который реализует вышеупомянутоеClient
интерфейс:
public class DataClient implements Client {
private RestTemplate restTemplate = new RestTemplate();
private ExecutorService executor = Executors.newFixedThreadPool(10);
// for synchronous call
@Override
public DataResponse executeSynchronous(DataKey key) {
DataResponse dataResponse = null;
Future<DataResponse> future = null;
try {
future = executeAsynchronous(key);
dataResponse = future.get(key.getTimeout(), TimeUnit.MILLISECONDS);
} catch (TimeoutException ex) {
PotoLogging.logErrors(ex, DataErrorEnum.TIMEOUT_ON_CLIENT, key);
dataResponse = new DataResponse(null, DataErrorEnum.TIMEOUT_ON_CLIENT, DataStatusEnum.ERROR);
// does this looks right?
future.cancel(true); // terminating tasks that have timed out
} catch (Exception ex) {
PotoLogging.logErrors(ex, DataErrorEnum.CLIENT_ERROR, key);
dataResponse = new DataResponse(null, DataErrorEnum.CLIENT_ERROR, DataStatusEnum.ERROR);
}
return dataResponse;
}
//for asynchronous call
@Override
public Future<DataResponse> executeAsynchronous(DataKey key) {
Future<DataResponse> future = null;
try {
Task task = new Task(key, restTemplate);
future = executor.submit(task);
} catch (Exception ex) {
PotoLogging.logErrors(ex, DataErrorEnum.CLIENT_ERROR, key);
}
return future;
}
}
Простой класс, который будет выполнять актуальную задачу:
public class Task implements Callable<DataResponse> {
private DataKey key;
private RestTemplate restTemplate;
public Task(DataKey key, RestTemplate restTemplate) {
this.key = key;
this.restTemplate = restTemplate;
}
@Override
public DataResponse call() {
DataResponse dataResponse = null;
String response = null;
try {
String url = createURL();
response = restTemplate.getForObject(url, String.class);
// it is a successful response
dataResponse = new DataResponse(response, DataErrorEnum.NONE, DataStatusEnum.SUCCESS);
} catch (RestClientException ex) {
PotoLogging.logErrors(ex, DataErrorEnum.SERVER_DOWN, key);
dataResponse = new DataResponse(null, DataErrorEnum.SERVER_DOWN, DataStatusEnum.ERROR);
} catch (Exception ex) {
PotoLogging.logErrors(ex, DataErrorEnum.CLIENT_ERROR, key);
dataResponse = new DataResponse(null, DataErrorEnum.CLIENT_ERROR, DataStatusEnum.ERROR);
}
return dataResponse;
}
// create a URL by using key object
private String createURL() {
String url = somecode;
return url;
}
}
Когда я начал работать над этим решением, я не прекращал выполнение заданий, срок действия которых истек. Я сообщал клиенту об истечении времени ожидания, но задача продолжает выполняться в пуле потоков (потенциально занимающих один из моих ограниченных 10 потоков в течение длительного времени). Поэтому я провел некоторые онлайн-исследования и обнаружил, что могу отменить свои задачи, для которых истек срок ожидания, с помощью функции «Отмена на будущее», как показано ниже -
future.cancel(true);
Но если я делаю так, как показано в моем решении выше, то мне нужно закрыть другие ресурсы, такие какRestTemplate
как только поток прерывается? Если да, то как бы я это сделал? Кроме того, мы можем прерватьRestTemplate
звонки? Так как я попытался вызвать отмену в моем будущем, как только истекло время выполнения задачи, но я думаю, что мой поток не прерывался.
Должны ли мы всегда завершать задачи, для которых истекло время ожидания? Если мы этого не сделаем, то какое влияние я окажу? Повлияет ли это на мою производительность?
Есть ли лучшее решение для этого случая с моей текущей настройкой?