首页 > 解决方案 > 如果原始 ApiFuture / ListenableFuture 失败或取消,Futures.transform() lambda 参数是什么

问题描述

我有一个异步发送消息列表的方法。每次发送返回ApiFuture<String>(GCP 版本的 Guava's ListenableFuture)。我需要这个方法来返回一个Future<Boolean>,所以我

  1. 为每个创建一个列表依赖项ApiFuture<String>
  2. 将结果ApiFuture<List<String>>转换为Future<Boolean>usingApiFutures.transform方法

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

我的问题是:val如果一个或多个原始期货失败/取消,上述 lambda 参数的值是多少?在这种情况下甚至会调用 lambda 吗?

谢谢!

标签: javaasynchronousgoogle-cloud-platformguavafuture

解决方案


ApiFuture<V>在 type 上形成一个monadVtransform并将一个函数应用于 type 的封装值V。如果由于失败或取消ApiFuture<V>而不包含V值,则转换后的未来是相同的。

如果您想处理由于异常而导致的失败,您可以使用它ApiFutures.catching()来产生替代结果(例如Boolean.FALSE)。

如果您想将取消转换为成功的值,我相信您需要ApiFuture.addListener直接使用,并让侦听SettableApiFuture器完成您返回的 a 。然后监听器(当源未来被取消时将被调用)可以检查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;
}

推荐阅读