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

使用Spring Webclient实现Scatter&Gather时如何处理单服务异常

问题解决方案

现有实现存在的问题

  • 线程安全风险:你在zip的map操作中修改外部定义的ArrayList,响应式操作符的执行没有固定线程绑定,多线程场景下会出现并发修改异常或数据丢失。
  • 错误传播不符合预期:Mono.zip的原生特性是任意上游Mono触发错误信号,整个zip流就会直接抛出异常终止,这是你遇到单个服务失败整体报错的核心原因。
  • 语法BUG:前面定义的两个Mono变量是gResp、iResp,zip时使用了未定义的firstResp、secResp;第二个if判断后多了多余的分号,会导致后续addAll无论判断结果是否成立都会执行。

优化后可实现部分失败降级的代码

public Mono<List<Response>> getRecords(String input) {
    // 第一个服务调用,出错返回空集合
    Mono<List<Response>> firstRespList = this.firstWebClient.get().uri(uriBuilder -> uriBuilder
                    .path("/")
                    .queryParam("q", input)
                    .build())
            .retrieve()
            .bodyToMono(FirstApiResponse.class)
            .log()
            .timeout(Duration.ofSeconds(50L))
            .map(Mapper::convert)
            // 捕获所有异常降级返回空集合,可在此处添加错误日志打印
            .onErrorResume(ex -> Mono.just(Collections.emptyList()));

    // 第二个服务调用,出错返回空集合
    Mono<List<Response>> secondRespList = this.secondWebClient.get().uri(uriBuilder -> uriBuilder
                    .path("/search")
                    .queryParam("term", input)
                    .build())
            .retrieve()
            .bodyToMono(SecondApiResponse.class)
            .log()
            .timeout(Duration.ofSeconds(50L))
            .map(Mapper::convert)
            // 捕获所有异常降级返回空集合,可在此处添加错误日志打印
            .onErrorResume(ex -> Mono.just(Collections.emptyList()));

    // 合并两个结果返回
    return Mono.zip(firstRespList, secondRespList)
            .map(tuple -> {
                List<Response> result = new ArrayList<>();
                result.addAll(tuple.getT1());
                result.addAll(tuple.getT2());
                return result;
            });
}

// Mapper方法保持不变即可
public static List<Response> convert(FirstApiResponse resp) {
    // 原有转换逻辑
    return response;
}

public static List<Response> convert(SecondApiResponse resp) {
    // 原有转换逻辑
    return response;
}

关键改动说明

  • 每个独立服务调用后添加onErrorResume降级逻辑,不管是超时、HTTP报错、序列化失败都不会向上传播错误,只会返回空集合,完全满足单个服务失败时仍返回另一个服务结果的需求。
  • 提前完成响应结构转换,zip时只需合并集合即可,逻辑拆分更清晰。
  • 去掉了外部可变集合,所有结果拼接都在zip的map操作内部完成,彻底规避线程安全问题。

内容的提问来源于stack exchange,提问作者Andromeda

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 13:45:03