Что такое лямбда-аргумент Futures.transform () в случае сбоя или отмены исходного ApiFuture / ListenableFuture - PullRequest
0 голосов
/ 18 октября 2018

У меня есть метод, который асинхронно отправляет список сообщений.Каждое послание возвращает ApiFuture<String> (GCP-версия Guava's ListenableFuture).Мне нужен этот метод для возврата одного Future<Boolean>, поэтому я

  1. Создаю зависимость списка для каждого ApiFuture<String>
  2. Преобразуем полученный ApiFuture<List<String>> в Future<Boolean>, используя ApiFutures.transform method

ApiFuture< List < String > > allSentFuture = ApiFutures.allAsList(futures);
return ApiFutures.transform(allSentFuture, val -> { 
        return true; 
    }, 
    Executors.newCachedThreadPool()
);

Мой вопрос: каково значение val аргумента лямбды выше, если один или несколько из исходных фьючерсов провалились / отменены?Лямбда вообще называется в этом случае?

Спасибо!

1 Ответ

0 голосов
/ 18 октября 2018

ApiFuture<V> образует монаду над типом V, а transform применяет функцию к инкапсулированному значению типа V.Если ApiFuture<V> не содержит значение V из-за его сбоя или отмены, преобразованное будущее будет таким же.

Если вы хотите обрабатывать сбои из-за исключений, вы можете использовать ApiFutures.catching()вместо этого вывести альтернативный результат (например, Boolean.FALSE).

Если вы хотите преобразовать отмену в успешное значение, я полагаю, что вам нужно было бы использовать ApiFuture.addListener напрямую и заставить слушателя выполнить SettableApiFuture которые вы возвращаете.Затем слушатель (который будет вызываться при отмене будущего источника) может проверить isCancelled, чтобы обнаружить этот случай, или может перехватить и обработать CancellationException.

Например:

/**
 * Adapt an iterable of {@link ApiFuture} instances into a single {@code ApiFuture}.
 */
static <T> ApiFuture<Boolean> adaptFutures(Iterable<ApiFuture<T>> futures) {
    final SettableApiFuture<Boolean> result = SettableApiFuture.create();
    final ApiFuture<List<T>> allFutures = ApiFutures.allAsList(futures);
    allFutures.addListener(
        () -> {
            if (allFutures.isCancelled()) {
                result.set(Boolean.FALSE);
                return;
            }
            try {
                allFutures.get();
                result.set(Boolean.TRUE);
            } catch (ExecutionException | InterruptedException ex) {
                // Maybe log something here?
                //
                // Note that InterruptedException is actually impossible here
                // because we're running in the listener callback, but the API
                // still marks it as potentially thrown by .get() above.
                //
                // So if we reach here it means that the allAsList future failed.
                result.set(Boolean.FALSE);
            }
        },
        // Not normally safe, but we know our listener runs fast enough
        // to run inline on the thread that completes the last future.
        Runnable::run);
    return result;
}
...