CompletableFuture thenCompose после исключительно

Я застрял с обработкой исключений CompletableFuture

Моя логика - отправить электронное письмо и сохранить статус этого действия. Если отправка электронной почты вызывает исключение, мне нужно сохранить статус с сообщением об исключении.

public interface MyService {
CompletableFuture<Boolean> sendEmail(String content, String address);
CompletableFuture<StatusResult> saveStatus(String content, String address);}

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

@Component
public class Processor {
    private static final Logger LOGGER = LoggerFactory.getLogger(Processor.class);
    @Autowired
    private MyService myService;

    public CompletableFuture<StatusResult> sendEmail(String content, String address) {
        AtomicReference<String> error = new AtomicReference<>();// just to forward error message from exception block to thenCompose
        return myService.sendEmail(content, address).exceptionally(e -> {
            LOGGER.error("Exception during send email ", e);
            error.set(e.getMessage());
            return null;
        }).thenCompose(x -> {
            if (x == null) {
                return myService.saveStatus(error.get(), address);
            } else {
                return myService.saveStatus("good", address);
            }
        });

    }
}

Похоже, что метод ручка должен помочь, но он возвращает CompletableFuture или CompletableFuture

 public CompletableFuture<StatusResult> sendEmail(String content, String address) {
    CompletableFuture<CompletableFuture<StatusResult>> result = myService.sendEmail(content, address).handle((x, e) -> {
        if (e != null) {
            LOGGER.error("Exception during send email ", e);
            return myService.saveStatus("error", address);
        } else {
            return myService.saveStatus("good", address);
        }
    });
}

Вам не нужны два CompletableFutures. sendEmail уже запущен в отдельном потоке, просто пусть он дождется saveStatus и вернет результат.

Dane White 26.10.2018 19:17

Я вообще не могу блокировать, потому что он работает с Spring WebFlux. Блокировка повлияет на все запросы

Aleksandr Filichkin 26.10.2018 19:33
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
2
1 152
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Другое рабочее решение:

public CompletableFuture<StatusResult> sendEmailAndSaveStatus(String content, String address) {
    CompletableFuture<Boolean> sendEmail = myService.sendEmail(content, address);
    CompletableFuture<StatusResult> result = new CompletableFuture<>();
    sendEmail.exceptionally(e -> {
        LOGGER.info("Exception during send email ");
        myService.saveStatus(e.getMessage(), address).thenApply(x -> result.complete(x));
        return false;
    });
    sendEmail.thenCompose(x -> myService.saveStatus("good", address)).thenApply(x -> result.complete(x));
    return result;
}

Это не сработает, потому что вы связываете два обработчика (этапов завершения) с одним и тем же CompletableFuture<> sendEmail - один из них произойдет, а другой - нет. Кроме того, вместо создания второго завершаемого будущего вы можете просто использовать thenApply для преобразования одного в другой тип.

Guss 02.12.2018 22:22
Ответ принят как подходящий

Вы можете заранее преобразовать в свой статус сохранения.

public CompletableFuture<String> sendEmail(String content, String address) {

    return myService.sendEmail(content, address)
            .thenApply(b -> "good")
            .exceptionally(Throwable::getMessage)
            .thenCompose(status -> myService.saveStatus(status, address));
}

Очень элегантно. Престижность.

Guss 02.12.2018 22:22

Другие вопросы по теме