Flux not subscribing in Spring 5 reactor

后端 未结 1 1401
不知归路
不知归路 2021-02-09 17:09

I\'m probably missing something but I can\'t figure out what it is.

The following code does nothing at all:

webClient.get().uri(\"/some/path/here\").ret         


        
相关标签:
1条回答
  • 2021-02-09 17:54

    Short Answer

    subscribe does not block current thread, that means app main thread can complete earlier than Flux emits any element. So either use block or employ waiting in the main thread.

    Details

    Call to the no-args subscribe() just makes request(unbounded) on Flux without setting up any Subscriber. It triggers operation generally in a separate thread but does not block the current thread. Most likely, your main thread ends before WebClient received the response in that separate thread and passive side effect doOnNext(...) happened.

    To illustrate/test that operation is started, wait for some time in the main thread. Just put the following line right after subscribe() call:

    Thread.sleep(1000);
    

    Now, after playing with the timeout value, you'll be able to see result printed.

    Let's now implicitly ship a custom Scheduler for async operations and wait for all its tasks to be completed. Also, let's pass the System.out::println as subscribe(...) argument instead of doOnNext, so that complete code appears as follows:

    ExecutorService executor = Executors.newSingleThreadExecutor(); 
    
    webClient.get().uri("/some/path/here").retrieve()
        .bodyToMono(GetLocationsResponse.class)
        .publishOn(Schedulers.fromExecutor(executor)) // next operation will go to this executor
        .subscribe(System.out::println); //still non-blocking
    
    executor.awaitTermination(1, TimeUnit.SECONDS); //block current main thread 
    

    This example uses slightly different subscribe(Consumer). Most importantly, it adds publishOn(Scheduler) which is backed by ExecutorService. The latter is used then to wait for termination in the main thread.

    Surely, the much easier way to achieve the same result is to use block() as you mentioned initially:

    webClient.get().uri("/some/path/here").retrieve()
          .bodyToMono(GetLocationsResponse.class)
          .doOnNext(System.out::println)
          .block();
    

    Finally, note on your third example with Flux.just(...)...subscribe() - seems it just quickly completes before your main thread gets terminated. That's because it requires way less time to emit a few String elements compared to the emission of a single GetLocationsResponse element (implying timings for write request+read response+parse into POJO). However, if you make this Flux to delay elements, you'll get the same behavior reproduced:

    Flux.just("1", "2", "3")
        .filter(s -> !s.equals("2"))
        .delayElements(Duration.ofMillis(500)) //this makes it stop printing in main thread
        .doOnNext(System.out::println)
        .subscribe(); 
    
    
    Flux.just("1", "2", "3")
        .filter(s -> !s.equals("2"))
        .delayElements(Duration.ofMillis(500))
        .doOnNext(System.out::println)
        .blockLast(); //and that makes it printing back again
    
    0 讨论(0)
提交回复
热议问题