You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Mono.error存入Caffeine的AsyncLoadingCache?

问题描述

以下是相关代码示例:

AsyncLoadingCache<String, String> cache = Caffeine.newBuilder().buildAsync(
  (String k, Executor e) ->
    doThingReturnsMono()
      .subscribeOn(Schedulers.fromExecutor(e))
      .toFuture()
);

cache.put("fail", Mono.error<String>(new RuntimeException()).toFuture());
cache.put("success", Mono.just("success").toFuture());

System.err.println(cache.asMap().getKeys()); // Prints ["success"]

从输出可见,调用cache.put存入Mono.error转换的Future时,缓存仅保留了成功的键值对。请问如何实现将Mono.error存入AsyncLoadingCache?

解决方案

Caffeine的AsyncLoadingCache默认会自动丢弃最终失败的Future对应的条目,因为它的设计目标是缓存成功计算的结果。要存储失败状态,你需要把错误包装成合法的缓存值,而非直接传递失败的Future。

具体实现步骤

  • 定义结果封装类:创建一个密封接口或类,用来同时承载成功值和错误信息,保证类型安全:
public sealed interface CacheResult<T> permits SuccessResult, ErrorResult {
    static <T> CacheResult<T> success(T value) {
        return new SuccessResult<>(value);
    }

    static <T> CacheResult<T> error(Throwable throwable) {
        return new ErrorResult<>(throwable);
    }
}

record SuccessResult<T>(T value) implements CacheResult<T> {}
record ErrorResult<T>(Throwable throwable) implements CacheResult<T> {}
  • 调整缓存泛型与操作逻辑:将缓存的泛型改为CacheResult<String>,在Mono流中统一包装结果或错误:
AsyncLoadingCache<String, CacheResult<String>> cache = Caffeine.newBuilder().buildAsync(
  (String k, Executor e) ->
    doThingReturnsMono()
      .map(CacheResult::success)
      .onErrorResume(ex -> Mono.just(CacheResult.error(ex)))
      .subscribeOn(Schedulers.fromExecutor(e))
      .toFuture()
);

// 存入失败结果
cache.put("fail", Mono.error(new RuntimeException())
        .map(CacheResult::success)
        .onErrorResume(ex -> Mono.just(CacheResult.error(ex)))
        .toFuture());

// 存入成功结果
cache.put("success", Mono.just("success")
        .map(CacheResult::success)
        .onErrorResume(ex -> Mono.just(CacheResult.error(ex)))
        .toFuture());
  • 读取缓存时处理结果:根据封装类的类型分支处理成功或失败场景:
cache.get("fail").thenAccept(result -> {
    if (result instanceof SuccessResult<String> success) {
        System.out.println("成功值:" + success.value());
    } else if (result instanceof ErrorResult<String> error) {
        System.err.println("错误信息:" + error.throwable().getMessage());
    }
});

替代方案(无需自定义类)

如果不想自定义封装类,也可以用Pair<Optional<T>, Optional<Throwable>>这类通用容器,但自定义密封接口的可读性和类型安全性更优。

内容的提问来源于stack exchange,提问作者A Jar of Clay

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 08:59:55