Как остановить вызываемые задачи в службе Executor в случае возникновения исключения - PullRequest
0 голосов
/ 21 января 2020

Я пытаюсь реализовать пример приложения для тестирования интерфейсов Callable и ExecutorService.

В моем приложении у меня есть:

@Bean("fixedThreadPool")
public ExecutorService fixedThreadPool() {
    return Executors.newFixedThreadPool(5);
}

Затем:

public void removeUserIds(Set<String> userIds) {
 UriComponentsBuilder builder = UriComponentsBuilder.fromUriString("http://localhost:8080/remove");
    final List<Callable<String>> callables = new ArrayList<>();  
    userIds.forEach(userId -> {
        final Callable<String> task = () -> callServiceToRemove(builder,userId); //Call to remote service using RestTemplate
        callables.add(task);
    });

    try {
        final List<Future<String>> futureList =
            executor.invokeAll(callables);

        futureList.forEach(future -> {
            try {
                log.info(future.get());
            } catch (final Exception e) {
                log.error("Error : "+ e.getMessage());
            } 
        });
    } catch (final Exception e) {
        log.error("Error Error Error : "+ e.getMessage());
    } finally {
        executor.shutdown();
    }
}

Когда я вызываю метод removeUserIds () с 100 userIds, он работает нормально в счастливом потоке, но если служба недоступна или не работает, ошибка выводится в сотый раз. Я не могу остановить / прекратить поток, если служба недоступна или недоступна, поэтому дальнейший вызов не произойдет. Может ли кто-нибудь помочь здесь, чтобы решить эту проблему, как я могу остановить выполнение потока, если служба не работает, или предложить здесь возможное решение?

Ответы [ 2 ]

1 голос
/ 21 января 2020

Это скорее проблема дизайна, чем проблема кодирования. Там может быть несколько подходов. Вы можете взять этот пример, например:

Использовать глобальный флаг

Ищите глобальный логический флаг, скажем Globals.serviceUnavailable, прежде чем фактически запускать вызов удаленной службы. Этот глобальный флаг может быть установлен первыми службами, которые столкнулись с удаленной ошибкой. Вот изменения в коде.

final Callable<String> task = () -> {
   try{    
       if( !Globals.serviceUnavailable ) callServiceToRemove(builder,userId);
   }
   catch( ServiceUnavailableException e ){ //Or whatever your exception is
       Globals.serviceUnavailable = true; //Notify the remaining tasks that the service is unavailable.
   }

}

Конечно, вы должны увидеть если обновление значения Globals.serviceUnavailable должно быть синхронизировано. (Это может не потребоваться, если вы в порядке для частичного успешного удаления пакета пользовательских идентификаторов.)

Кроме того, это будет работать, только если ваш пул потоков намного меньше, чем количество отправленных задач, что я вижу, дело здесь.

1 голос
/ 21 января 2020

переместить вызов callServiceToRemove в блок try catch.

В блоке catch вы можете использовать executor.shutdownNow ();

shutdownNow () пытается остановить все активно выполняет задачи, останавливает обработку ожидающих задач и возвращает список задач, ожидающих выполнения. Этот метод не ожидает активного выполнения задач для завершения и пытается принудительно остановить их. Нет никаких гарантий, кроме попыток изо всех сил прекратить обработку активно выполняемых задач. Эта реализация отменяет задачи через Thread.interrupt (), поэтому любая задача, которая не отвечает на прерывания, может никогда не завершиться.

...