【问题标题】:Why is the Flux publisher doOnComplete method not being invoked?为什么没有调用 Flux 发布者 doOnComplete 方法?
【发布时间】:2020-05-06 20:28:41
【问题描述】:

我尝试在使用 Flux 发布者执行另一个方法后执行一个方法,但从未调用方法 doOnComplete。 代码如下:

public class Client implements Serializable {
    private Long id;
    private String category;
    // other properties, getters and setters
}

interface ClientRepository extends JpaRepository<Client,Long> {
    List<Client> findAllByCategory(String category);
    @Transactional
    void deleteByCategory(String category);
}

class ClientResponse {
    private Long status;
    private String message;
}

@Component
class ClientService {
    @Autowired
    ClientRepository clientRepository;
    @Autowired
    WebClient webClient;

  public Mono<ClientResponse> deleteRemoteClient(Long idClient) {
    return webClient.post()
      .uri("/api/remoteClient/{idClient}",idClient)
      .retrieve()
      .bodyToMono(ClientResponse.class)
      .doOnSuccess(ok -> System.out.println(
                          "Delete success for client= " + idClient))
      .doOnError(err -> System.out.println(
                          "Delete failed for client= " + idClient + ", err =" + err));
  }

  /**
   * Get All clients by category, then delete them remotely one by one.
   * When everything goes well, delete all clients locally in one shot by category
   **/
  public Flux<ClientResponse> deleteLocalClientByCategory(String category) {
    return Flux.fromStream(clientRepository.findAllByCategory(category).stream())
      .flatMap(client -> deleteRemoteClient(client.getId()))
      .doOnComplete(() -> clientRepository.deleteByCategory(category));
  }
}

@Component
class ClientHandler {
    @Autowired 
    ClientService service;

    public Mono<ClientResponse> deleteByCatgeory(ServerRequest request) {
        return service.deleteLocalClientByCategory(
                   Long.parseLong(request.queryParam("category").get()))
               .publishNext()
               .flatMap(response -> ServerResponse.ok().build());
    }
}

正如我之前提到的,方法deleteRemoteClient(client.getId()) 但不是clientRepository.deleteByCategory(category)

【问题讨论】:

  • 通量订阅的地点/时间?
  • @DarrenForsythe 你的意思是订阅必须在 deleteRemoteClient(client.getId()) 上完成,返回一个 Mono?
  • 我的意思是整个链条,deleteLocalClientByCategory在哪里调用?
  • @DarrenForsythe 我更新了帖子,看看我在哪里打电话给deleteLocalClientByCategory
  • JpaRepository 表示您正在使用阻塞数据库,这反过来又意味着您执行的每个数据库调用都是阻塞的,并且您的应用程序可能性能不佳,并且在中等期间存在线程饥饿的巨大风险加载。

标签: spring spring-boot spring-data-jpa spring-webflux


【解决方案1】:

当您调用publishNext 时,您会在第一个元素之后取消您的助焊剂。参见插图here

所以你的助焊剂永远不会完成。您应该使用doOnCanceldoFinally

【讨论】:

  • doFinally: onFinally 在终端信号(完成、错误 * 或取消)之后执行的回调,在我的情况下这是一个问题,因为我希望方法 clientRepository.deleteByCategory(category) 在 @ 之后立即运行987654327@ 编译成功,但如果有错误就不行!
【解决方案2】:

因此,为此目的使用.doOnComplite 不是一个好主意,请尝试.then 运算符,例如:

  ...
  .flatMap(client -> deleteRemoteClient(client.getId()))
  .then(clientRepository.deleteByCategory(category));

【讨论】:

  • Then 运算符必须采用 MonodeleteByCacetgory 是 void 方法,并且全局方法必须返回 Mono&lt;ClientResponse&gt; 类型的对象。
  • 我明白你的意思,但正如我之前所说,clientRepository.deleteByCategory(category) 将不起作用,因为 .doOnComplete() 没有订阅你的方法
  • 我有点迷茫,有没有办法在保持相同类型的回报的同时进行订阅?
  • 作为选项,您可以添加 .subscribe 运算符 .doOnComplete(() -> clientRepository.deleteByCategory(category).subscribe()) 它将起作用,但如果 deleteByCacetgory 失败,您可能会遇到问题跨度>
猜你喜欢
  • 2017-03-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-23
  • 1970-01-01
  • 2021-09-28
  • 2015-08-01
  • 1970-01-01
相关资源
最近更新 更多